home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / flxlstc.exe / FLC2.DOC < prev    next >
Text File  |  1992-07-12  |  193KB  |  6,002 lines

  1. FLC2 is shareware meaning try before you buy.  If you use FLC2
  2. for other than evaluation purposes you are required to register.
  3. The registration fee is $65.  Upon registration you will be sent a
  4. hard copy manual and 3.5" DOS formatted diskette with the latest
  5. revisions and examples.  Thank you for supporting the shareware concept!
  6.  
  7.  
  8.  
  9.  
  10.                        FlexList for ANSI C
  11.  
  12.  
  13.                          Copyright 1990
  14.                           John W. Small
  15.                        All rights reserved
  16.  
  17.                       PSW / Power SoftWare
  18.                          P.O. Box 10072
  19.                    McLean, Virginia 22102 8072
  20.                          (703) 759-3838
  21.  
  22.                              10/4/90
  23.  
  24.  
  25.  
  26.                  CLAIM TO PROPRIETARY TECHNIQUES
  27.  
  28. Several features of FlexList used in combination make FlexList
  29. unique and versatile.  The hybrid stack-queue-list-array data
  30. structure and the techniques used to implement it as a generic
  31. polymorphic object can be easily ported to other computer
  32. languages and remain intact in their essence.  The author claims
  33. all rights to these features.
  34.                  Software License Agreement
  35.  
  36.  
  37. Power SoftWare licenses the bona fide purchaser of FlexList to
  38. use the tool in the development of software without royalty.  The
  39. licensee may not publish any portion of the tool kit and may only
  40. make backup copies of software and documentation as a means of
  41. protecting the licensee's investment against loss or damage.
  42.  
  43.  
  44.  
  45.                         Limited Warranty
  46.  
  47.  
  48. Power SoftWare warrants the FlexList toolkit to be free from
  49. defects in materials and workmanship for a period of 90 days from
  50. the original purchase date and will replace same if found to be
  51. defective and reported in writing to PSW within this period.  The
  52. fitness of the FlexList toolkit for any particular application is
  53. not implied nor guaranteed.  All other liabilities which may be
  54. construed are specifically disclaimed except where required by
  55. law.
  56.  
  57.  
  58.  
  59.                           Registration
  60.  
  61.  
  62. Please fill out and return the registration post card.  Print
  63. your name, address, serial number, date and place of purchase. 
  64. Notices of updates and new example diskettes are mailed from the
  65. registration roster.  Thank you!
  66.  
  67.                         Acknowledgments
  68.  
  69.  
  70. I wish to thank those FlexList customers that have contributed to
  71. the present form of FlexList, Bruce Vantassel, President of
  72. Intellisys Corporation, Miami, Florida, for his suggestions and
  73. advice on adding sorting and searching functions and advice on
  74. revising this manual and to Milton Palmer, Senior Scientist of
  75. Ramsearch Company, College Park, Maryland, for his suggestions
  76. and advice on more efficient sorting and searching by placing the
  77. compare function pointer inside the FlexList header, and his
  78. advice on more efficient copying operations, and specifically his
  79. suggestion on making the find functions a combination of linear
  80. and binary searches.
  81.  
  82. Thanks also to all you early FlexList customers, who believed in
  83. parameterized list primitives even before OOP became a buzz word;
  84. you have kept FlexList alive these first six years: from its
  85. first inception and implementation in Turbo Pascal 2.0.
  86.  
  87. Special thanks to my mother for her patience in letting me use
  88. her home to start PSW and listening to me go on hour after hour
  89. about how useful FlexList would be to overworked programmers. 
  90.  
  91. Lastly I wish to thank my Lord and Savior, Jesus Christ, who give
  92. himself for me, that I might live.
  93.                            Contents
  94.  
  95.  
  96. Introduction
  97.  
  98.  
  99. Chapter  1.    Getting Started . . . . . . . . . . . . . . . . .9
  100.  
  101. Chapter  2.    Programming with FlexList . . . . . . . . . . . 11
  102.  
  103. Chapter  3.    FlexList Reference. . . . . . . . . . . . . . . 29
  104.  
  105. Appendix A.    Common Mistakes . . . . . . . . . . . . . . . .107
  106.  
  107. Appendix B.    Inside FlexList . . . . . . . . . . . . . . . .109
  108.  
  109. Appendix C.    FlexList Source Code. . . . . . . . . . . . . .113
  110.  
  111.  
  112. Index
  113.                          Introduction
  114.  
  115.  
  116. Anytime your C application requires a stack, queue, or linked
  117. list, simply include flexlist.h in your source code and then
  118. start defining your stack, queue, and/or list variables as type
  119. FlexList.  A FlexList can be initialized, by various constructor
  120. functions, to store any type of data and then accessed as a
  121. stack, queue, list, or even an array interchangeably!
  122.  
  123. With more than 30 FlexList functions to choose from, you can
  124. push, pop, insert, delete, sort, store, recall, or find, to name
  125. but a few.  Access your data by value (copy) or by reference
  126. (pointer).  Or move nodes directly between FlexLists.  Because
  127. FlexList functions adjust automatically to different types of
  128. data, new sets of primitives needn't be derived to accommodate
  129. new data types.  Thus your application's coding time and code
  130. size won't continue to grow when you add new types of FlexLists. 
  131. A FlexList can even be made to accommodate heterogeneous data via
  132. its virtual function hooks.
  133.  
  134. With FlexList you can quickly construct lists of lists or other
  135. composite structures.  And since FlexLists are initialized at run
  136. time, the data they hold or even their creation can be specified
  137. at run time thus allowing your application new dimensions of
  138. adaptability to user inputs.  
  139.  
  140. Use FlexList to code your next application's linked lists in
  141. minutes instead of days, without the usual debugging and
  142. documenting headaches associated with custom coding various list
  143. types.  It's no problem modifying your application in midstream
  144. to incorporate various and differing list types; with FlexList no
  145. linked list code needs to be scrapped or rewritten.  The code
  146. space you'll save over cloning list primitives for different data
  147. types may just save you from having to go the overlay/swapping
  148. route.
  149. Chapter  1.  Getting Started
  150.  
  151.  
  152. The distribution diskette contains the source code for FlexList:
  153.  
  154.      flexlist.h          //  ANSI C version
  155.      flexlist.c
  156.  
  157.      flexlist.hkr        //  K&R version
  158.      flexlist.ckr
  159.  
  160. Copy these to the appropriate directories for the C compiler and
  161. operating system you are using.  You may need to rename these
  162. files to suit your compiler.
  163.  
  164. For those of you who don't have smart linker/librarians on your
  165. system, I've broken down the FlexList functions into individual
  166. files and placed them into the following subdirectories:
  167.  
  168.      flansic.src
  169.      flkrc.src
  170.  
  171. You will find makefiles in each subdirectory.  Edit the macros in
  172. the makefile to suit your environment.  A FlexList library can be
  173. quickly built for your compiler using the makefile.
  174.  
  175. Be sure to read the readme.doc file on the distribution diskette
  176. for the latest revision information.
  177.  
  178. Note:  FlexList is also available for C++.
  179. Chapter  2.  Programming with FlexList
  180.  
  181.  
  182. This chapter is a combination of a brief tutorial on using the
  183. FlexList tool and a logical survey of the FlexList functions. 
  184. You may find it useful to lookup the FlexList functions in the
  185. reference chapter while reading the example programs here.  Don't
  186. worry too much about the details for now.  Instead you should
  187. finish this chapter with 
  188.  
  189. 1)   an idea of the points to remember when programming with
  190.      FlexList, 
  191.  
  192. 2)   a conceptual model of FlexList's hybrid stack-queue-list-
  193.      array data structure, and
  194.  
  195. 3)   an appreciation for the various ways that a FlexList can be
  196.      manipulated and accessed, namely: by value, by reference, or
  197.      by node.
  198.  
  199. After programming for a while with FlexList, be sure to reread
  200. this chapter.
  201.  
  202. Let's first cover several points that you should keep in mind
  203. when using FlexList in any application.
  204.  
  205. 1.   Include flexlist.h in any application using FlexList.  
  206.  
  207.           #include <flexlist.h>
  208.  
  209. 2.   Define your stack, queue, or list as a FlexList.
  210.  
  211.           FlexList intStack;
  212.  
  213. 3.   Before using your FlexList you must call a constructor
  214.      function to initialize it for the size of the data that you
  215.      will be storing in it.
  216.  
  217.           FLfixed(&intStack,sizeof(int));
  218.  
  219. 4.   The address of your FlexList must be passed as the first
  220.      parameter to FlexList functions.   Where data copying is
  221.      involved, the address of the data is passed as the second
  222.      parameter.  Remember, don't pass the data by value.
  223.  
  224.           for (i = 1; i < 11; i++)
  225.                FLpushD(&intStack,&i);   /* address of i */
  226.  
  227. 5.   FlexList functions return pointers or integers.  A returned
  228.      value of zero indicates failure of the function to carry out
  229.      its task.
  230.  
  231.           while (FLpopD(&intStack,&i)) /* loop until false */
  232.                printf("\n %d",i);
  233.  
  234. 6.   After you are finished with your FlexList you should call a
  235.      FlexList destructor function.  In our example it isn't
  236.      really necessary since we've popped all the nodes anyway. 
  237.      Let's include it though for completeness.
  238.  
  239.           FLclear(&intStack);
  240.  
  241. 7.   Don't forget to link your application with the object module
  242.      created by compiling flexlist.c or with the library you
  243.      build.
  244.  
  245. Let's see the whole program.
  246.  
  247.  
  248.      #include <stdio.h>       /*  printf()  */
  249.      #include <flexlist.h>
  250.  
  251.      main()  /*  Count backwards from ten via a stack. */
  252.      {
  253.           FlexList intStack;
  254.           int i;
  255.  
  256.           (void) FLfixed(&intStack,sizeof(int));
  257.           for (i = 1; i < 11; i++)
  258.                (void) FLpushD(&intStack,&i);
  259.           while (FLpopD(&intStack,&i))
  260.                (void) printf("\n %d",i);
  261.           (void) FLclear(&intStack);
  262.           return 0;
  263.      }
  264.  
  265.  
  266.                   Dynamic FlexList Constructors
  267.  
  268. Let's continue with a survey of FlexList's various functions. 
  269. The FlexList tool has several constructor/destructor functions. 
  270. Why?  Well the FlexList that we just used in the previous example
  271. is a local variable.  Actually only the FlexList header is a
  272. local variable - the nodes in a FlexList are almost always
  273. dynamically allocated!  Suppose that we want the FlexList
  274. variable itself to be dynamically allocated?  Then we would use
  275. the constructor function FLfixedNew.
  276.  
  277. Let's see that program again.
  278.  
  279.      #include <stdio.h>       /*  printf()  */
  280.      #include <flexlist.h>
  281.  
  282.      main()  /*  Count backwards from ten via a stack. */
  283.      {
  284.           FlexL intS;
  285.           int i;
  286.  
  287.           if ((intS = FLfixedNew(sizeof(int),0,FLDdestruct0))
  288.                == FlexL0)  return 1;
  289.           for (i = 1; i < 11; i++)
  290.                (void) FLpushD(intS,&i);
  291.           while (FLpopD(intS,&i))
  292.                (void) printf("\n %d",i);
  293.           (void) FLdelete(&intS);
  294.           return 0;
  295.      }
  296.  
  297. Notice that the integer stack is now defined as type FlexL
  298. instead of FlexList.  FlexL is a pointer to a FlexList.  I
  299. contracted intStack to intS also as a reminder that it is a
  300. pointer to a FlexList and not a FlexList.  The constructor
  301. function FLfixedNew returns a pointer to the FlexList it
  302. allocates and initializes, otherwise it returns 0 or more
  303. specifically (FlexL) 0.  I've contracted all NULL constants and
  304. defined them in flexlist.h, e.g. (FlexL) 0 is FlexL0.  Several
  305. additional parameters are also required by FLfixedNew but don't
  306. worry about that now.  Please note that FlexList primitives take
  307. a FlexList pointer as their first parameter, with the exception
  308. of FLdelete.  That's why I didn't use the address of operator,
  309. "&", with "intS" in this version like I did with "&intStack" in
  310. the first.
  311.  
  312. The point of the two previous examples is that FlexList
  313. constructor/destructor functions come in two varieties: those
  314. that construct/destruct FlexList variables defined at compile
  315. time, i.e. local, static, and global variables, versus their
  316. counter parts that construct/destruct FlexList variables
  317. dynamically allocated at run time.
  318.  
  319.             FlexList Constructor/Destructor Functions
  320.  
  321. 1.   Constructor/destructor functions for FlexLists defined at
  322.      compile time:
  323.  
  324.  
  325.           FLfixed()      FLunpack()     FLvariant()
  326.           FLstr()        FLclear()
  327.  
  328.  
  329. 2.   Constructor/destructor functions for FlexLists allocated at
  330.      run time:
  331.  
  332.  
  333.           FLfixedNew()   FLunpackNew()  FLvariantNew()
  334.           FLstrNew()     FLdelete()
  335.  
  336.  
  337. The FLunpack and FLunpackNew functions are used to explode C
  338. arrays (vectors) into FlexLists.  Each FlexNode holds one cell of
  339. the array (see section on compaction functions).  FLvariant and
  340. FLvariantNew construct FlexLists that have variant sized
  341. FlexNodes (see FLvariant in reference chapter to see how to
  342. construct heterogeneous FlexLists)!  FLstr and  FLstrNew are
  343. actually macros that call FLvariant and FLvariantNew
  344. respectively, constructing FlexLists that contain FlexNodes just
  345. big be enough to hold C strings within.  FLclear deallocates all
  346. FlexNodes in a FlexList, while FLdelete calls FLclear and then
  347. proceeds to deallocate the dynamically allocated FlexList
  348. variable (header).
  349.  
  350.  
  351.                 FlexList Header Access Functions
  352.  
  353. As you become more familiar with what's inside a FlexList you
  354. will want to access the data fields inside the FlexList header. 
  355. Never access these fields directly!  There is little performance
  356. penalty since most of these functions are in fact macros.  You
  357. should decide right now that you are only going to access the
  358. guts of a FlexList via FlexList functions.  This insures the
  359. integrity of the FlexList by imposing the OOP (Object Oriented
  360. Programming) concept of encapsulation.  The C language doesn't
  361. enforce access restriction as does the C++ language, so you're on
  362. the honor system!
  363.  
  364.  
  365.      FLfrontD()          FLcurrentD()        FLrearD()
  366.      FLcurNum()          FLnodes()           FLmaxNodes()
  367.      FLsetMaxNodes()     FLnotFull()         FLsizeofNodeData()
  368.      FLisSorted()        FLunSort()          FLcompare()
  369.      FLsetCompare()      FLisFixed()         FLisVariant()
  370.      FLData()
  371.  
  372.  
  373. A FlexList can be accessed as a stack, queue, list, or even an
  374. array once it has nodes in it, interchangeably.  The FlexList
  375. header keeps track of everything so if your pushing data onto
  376. your "stack" at one moment, you can recall an element from your
  377. "array" the next.  You can sort your FlexList, then perform
  378. various other operations on it and FLisSorted will tell you if it
  379. is still sorted.  You can set an upper limit on the number of
  380. nodes a FlexList is allowed to hold with FLsetMaxNodes.  You will
  381. come to know what each function does with time.
  382.  
  383.  
  384.                FlexList Stack and Queue Functions
  385.  
  386. A stack provides LIFO (Last In, First Out) storage.  A complete
  387. set of stack primitives is provided.  These functions don't
  388. disturb the queue, list, or array structure of a FlexList.  In
  389. other words, you can access your FlexList as a stack at any time
  390. and revert back to accessing it as a queue, list, or array
  391. freely.
  392.  
  393.  
  394.      FLpushN()           FLpushD()           FLpopN()
  395.      FLpopD()            FLtopD()            FLinsQN()
  396.      FLinsQD()           FLfrontD()          FLrearD()
  397.  
  398.  
  399. A queue provides FIFO (First In, First Out) storage.  Notice that
  400. some of the stack functions double up here as queue functions,
  401. e.g. FLpopD, FLtopD.  Also I have again included some of the
  402. FlexList header access functions, i.e. FLfrontD and FLrearD which
  403. return pointers to the data in the first and last nodes
  404. respectively.  Basically I'm suggesting various logical ways to
  405. categorize FlexList functions to help you remember them.  You'll
  406. find that several functions may belong in multiple categories.
  407.  
  408. The functions ending with "N" work directly with the FlexNodes
  409. which contain your data.  For an example, suppose that you want
  410. to pop your stack directly into your queue.  The following code
  411. shows how.
  412.  
  413.      #include  <stdio.h>      /*  printf()  */
  414.      #include  <flexlist.h>
  415.  
  416.      FlexList s, q;
  417.      int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  418.      int *iptr;
  419.      #define  inT0   ((int *)0)
  420.  
  421.      main()         /*  count to ten the hard way  */
  422.      {
  423.           (void) FLunpack(&s,sizeof(a[0]),sizeof(a)/
  424.                sizeof(a[0]),a);
  425.           (void) FLfixed(&q,FLsizeofNodeData(&s));
  426.           while ((iptr = FLinsQN(&q,FLpopN(&s))) != inT0)
  427.                (void) printf("\n  %d",*iptr);
  428.           (void) FLclear(&s);
  429.           (void) FLclear(&q);
  430.           return 0;
  431.      }
  432.  
  433. In this example the stack is constructed by "exploding" an array
  434. of integers into a FlexList.  Next the queue is constructed to
  435. hold the same size data as the stack.  Then the stack is popped
  436. directly into the queue and a pointer to the data in the newly
  437. inserted queue node is captured and tested to control the
  438. looping!  I print the integer each time so you can see that it
  439. made it into the queue.  Did you notice how I defined the NULL
  440. integer pointer?  I did that here so you'll know what's going on
  441. when you see other NULL pointers elsewhere.
  442.  
  443.  
  444.                      FlexList List Functions
  445.  
  446. Any FlexList can be treated as a doubly linked list thereby
  447. providing sequential storage.  You can insert nodes or delete
  448. them.  The FlexList header maintains a current node pointer that
  449. lets the list functions know where the insertion or deletion is
  450. to take place.  Stack and queue functions don't disturb this
  451. current pointer unless of course it points to the top/front of
  452. the stack/queue and that node is popped/removed.  In that case
  453. the current node becomes undefined.
  454.  
  455.  
  456.      FLmkcur()           FLinsN()            FLinsD()
  457.      FLinsSortN()        FLinsSortD()        FLdelN()
  458.      FLdelD()            FLnextD()           FLprevD()
  459.      FLcurNum()          FLcurrentD()        FLcompare()
  460.      FLsetCompare()
  461.  
  462.      
  463. FlexList nodes are numbered starting at one.  When FLnextD
  464. reaches the end of the list the current node number is set to
  465. zero which is said to be undefined and FLnextD returns the NULL
  466. void pointer.  On the next call to FLnextD the current node
  467. becomes one, that is of course if there are nodes in the
  468. FlexList!  FLprevD works the same way.  This mechanism makes it
  469. handy to walk around lists pausing at the ends.  If you want to
  470. set the current pointer to a particular node, use FLmkcur.
  471.  
  472. Oh, I guess I should mention again that you can store any type of
  473. data in a FlexList not just integers.  Let's see something like
  474. that last example again with strings.
  475.  
  476.  
  477.      #include  <stdio.h>      /*  printf()  */
  478.      #include  <flexlist.h>
  479.  
  480.      FlexList l;
  481.      char *a[] = { "Now is the time", "for all good",
  482.           "programmers to cut", "their coding time",
  483.           "with FlexList!"
  484.      };
  485.      char **sptr;
  486.      #define chaRR0 ((char **)0)
  487.  
  488.      main()    /*  PSW propaganda  */
  489.      {
  490.           
  491.           (void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
  492.                sizeof(a[0]),a);
  493.           while ((sptr = FLnextD(&l,(void *)0)) != chaRR0)
  494.                (void) printf("\n  %s",*sptr);
  495.           (void) FLmkcur(&l,FLnodes(&l));
  496.           while (FLdelD(&l,(void *)0))
  497.                /* null statement */;  /*  FLclear(&l);  */
  498.           (void) printf("\n There should be zero nodes now: %d",
  499.                FLnodes(&l));
  500.           return 0;
  501.      }
  502.  
  503.  
  504. In this program I exploded a vector of char pointers into a
  505. FlexList.  Whenever FlexLists are constructed the current node is
  506. set as undefined so FLnextD starts walking across the FlexList
  507. beginning with the first node.  FLnextD will copy the data in the
  508. next node to whatever address you specify in the second parameter
  509. unless of course it is the NULL address!  When you are browsing
  510. the reference chapter you will notice many FlexList functions
  511. that copy data to/from a FlexNode when an address is given.  If
  512. the NULL address is specified the copying action is inhibited but
  513. the function otherwise performs its purpose.  In this example FLnextD is inhibited from copying any data but it never the less
  514. moves the current pointer on to the next node.  FLnextD also
  515. returns a void pointer to the data in the next node.  I capture
  516. that pointer in order to print the string but I'm also using it
  517. to control the loop.
  518.  
  519. All FlexList functions return either pointers or integer types
  520. that are non zero only when the respective function completes
  521. successfully.  The void pointers returned from FlexList functions
  522. point to the user data in focus.  In the case of FLnextD it
  523. points to the user data in the next node.  I have simply type
  524. casted this pointer to a pointer to the type of data I'm storing
  525. in the FlexNodes in order to gain access to that data.  As you
  526. can see FlexList functions allow you to access you data by value
  527. (copy) or by reference (pointer) as well as moving nodes directly
  528. between/within FlexLists.
  529.  
  530. Back to our example, FLmkcur moves the current node pointer to
  531. the last node in the list.  FLmkcur also returns a pointer to the
  532. data in the last node but I choose to ignore it.  Now FLdelD is
  533. used to delete the nodes from the list.  FLdelD removes the
  534. current node after copying its contents to the address specified
  535. (copying is inhibited here by the NULL address) and then unlinks
  536. the FlexNode from the FlexList and proceeds to deallocate it
  537. making the previous node in the FlexList the new current node.  I
  538. might add that FLinsD does the exact opposite, i.e. inserts a new
  539. FlexNode after the current node making the new node current. 
  540. Again the stack and queue structure of FlexList is undisturbed by
  541. any list functions invoked on the FlexList and vice versa.
  542.  
  543.  
  544.                  FlexList Search/Sort Functions
  545.  
  546. The Search/Sort functions allow you to lookup and/or sort your
  547. data.  Every FlexList has a user definable compare function.  Use
  548. FLsetCompare to set a FlexList's internal compare function
  549. pointer.  To facilitate sorting define your compare function to
  550. return -1, 0, or 1 to indicate whether the first data being
  551. compared is less than, equal to, or greater than the second,
  552. respectively.  The compare function is also used for matching in
  553. the FLfind...() functions.  Please note that most of the
  554. functions mentioned here modify the current node setting, thus
  555. they interact with the list functions mentioned earlier.
  556.  
  557.  
  558.      FLinsSortN()        FLinsSortD()        FLfindFirstD()
  559.      FLfindNextD()       FLfindLastD()       FLfindPrevD()
  560.      FLsort()            FLisSorted()        FLunSort()
  561.      FLcompare()         FLsetCompare()
  562.  
  563.  
  564. Use FLinsSortD/N() to perform insertion sorts.  If the list isn't
  565. sorted then FLsort will be called automatically before attempting
  566. the insertion.  If a compare function pointer hasn't been setup
  567. then the insertion is aborted.
  568.  
  569. The FLfind...D functions work regardless if the FlexList is
  570. sorted or not.  If it is sorted then the binary search algorithm
  571. is used to find the first/last matching data and a linear search
  572. is used to find the next/previous match stopping immediately
  573. after the first mismatch.  If the FlexList is not sorted then the
  574. linear search algorithm is used to find the first/last matching
  575. data and again to find the next/previous match stopping only at
  576. the ends of the list.
  577.  
  578. Use FLsort or FLsetCompare to setup the compare function pointer. 
  579. If the NULL compare function pointer, FLcompare0 (defined in
  580. flexlist.h), is passed to FLsort then the previous compare
  581. function pointer is used to sort the list.  Call FLisSorted to
  582. determine whether a FlexList is still sorted from its last sort. 
  583. For example, suppose you sort a list and pop some nodes off the
  584. front.  Well that won't cause the FlexList to be unsorted so
  585. FLisSorted will return true.  But if you push some data onto it
  586. treating it like a stack, that may or may not ruin the sorted
  587. order.  FLisSorted will return false because it can no longer
  588. guarantee that the FlexList is sorted.  You need to be careful
  589. though since FLnextD, FLprevD, and FLmkcur won't cause FLisSorted
  590. to reset to false even though you might have modified the data in
  591. the FlexNode via the returned void pointer!  In that case you may
  592. want to call FLunSort to reset FLisSorted so that it will return
  593. false.
  594.  
  595. The following example performs an unsorted linear search followed
  596. by an alphabetical sort.
  597.  
  598.  
  599.      #include  <stdio.h>      /*  printf()  */
  600.      #include  <string.h>     /*  strstr(), strcmp()  */
  601.      #include  <flexlist.h>
  602.  
  603.      int strStr(char *s, char *t)
  604.      {
  605.           return !(int)strstr(s,t);
  606.      }
  607.  
  608.      main()
  609.      {
  610.           FlexList l;
  611.           char *s, sbuf[80];
  612.           char *mask = "overtime";
  613.           int i;
  614.  
  615.           (void) FLstr(&l);
  616.           (void) FLinsD(&l,"Once upon a time there were three");
  617.           (void) FLinsD(&l,"programmers, who worked");
  618.           (void) FLinsD(&l,"allot of overtime!");
  619.           (void) FLinsQD(&l,"That was before the FlexList Fox");
  620.           (void) FLinsQD(&l,"joined the staff!");
  621.           for ((void)FLmkcur(&l,0); FLnextD(&l,sbuf);
  622.                /* no reinit */)
  623.                (void) printf("\n Node: %d. %s",
  624.                     FLcurNum(&l),sbuf);
  625.           (void) FLsetCompare(&l,FLcomparE(strStr));
  626.           if ((s = FLfindFirstD(&l,mask)) != (char *)0)
  627.                (void) printf("\n Mask: \"%s\" found in \
  628.                     node: %d. %s",mask,FLcurNum(&l),s);
  629.           (void) FLsort(&l,FLcomparE(strcmp));
  630.           for (i = 1; FLrecallD(&l,sbuf,(unsigned)i); i++)
  631.                (void) printf("\n Node: %d. %s",
  632.                     FLcurNum(&l),sbuf);
  633.           (void) FLclear(&l);
  634.           return 0;
  635.      }
  636.  
  637.  
  638. This program constructs a variant FlexList via the macro
  639. constructor FLstr which expands into a call to FLvariant.  The
  640. FlexNodes in this FlexList are only be enough to hold the
  641. character strings passed as parameters (please note that
  642. character string constants are pointers to the strings so I
  643. didn't use the address of, "&", operator!)  I didn't use the
  644. FLunpack constructor because it builds fixed size FlexNode
  645. (homogeneous) FlexLists - an array has fixed cell sizes.  Instead
  646. I inserted the strings one by one and queued the last two just to
  647. be different.
  648.  
  649. The first "for loop" uses FLnextD to verify the contains of the
  650. FlexNodes.  FLnextD only copies the string and zero terminator
  651. thanks to the virtual function table's function pointers (see
  652. FLvariant in the reference chapter to see how to construct
  653. heterogenous lists).  Be sure that the variable whose address you
  654. pass to FLnextD is big enough to accommodate the largest data
  655. that can be read!   You should have noticed that I had to use
  656. FLmkcur(&l,0) since the current node pointer is still pointing to
  657. the last node inserted and not the last node queued.  Remember,
  658. queue functions don't disturb the list structure - the current
  659. node concept is part of the list structure, not the queue
  660. structure!
  661.  
  662. Since the list is not sorted, FLfindFirstD searches in a linear
  663. fashion starting with the first node, internally calling the
  664. compare function setup with FLsetCompare.  The FLcomparE macro,
  665. defined in flexlist.h, type casts strStr to the precise function pointer type required by both FLsetCompare and FLsort.  My strStr
  666. returns 0 if t is within s.  Since only a linear search will be
  667. used with this compare function, it doesn't matter that is
  668. doesn't return -1 or 1 to indicate less than or greater than.
  669.  
  670. The program proceeds with a standard alphabetical sort and the
  671. resultant ordering is displayed with FLrecallD, an array access
  672. function which you'll see in the next section.
  673.  
  674.  
  675.                     FlexList Array Functions
  676.  
  677. An array provides randomly accessible storage.  A FlexList can
  678. also be accessed as an array once it has nodes in it.
  679.  
  680.  
  681.      FLstoreD()          FLrecallD()         FLmkcur()
  682.      FLcurrentD()        FLcurNum()
  683.  
  684.  
  685. The last node accessed becomes the new current node.  When
  686. randomly accessing a FlexList, FLmkcur is called internally by
  687. both FLstoreD and FLrecallD to make the requested node current. 
  688. FLmkcur determines which pointer (front, current, or rear) is
  689. closest to the requested node.  It then follows the FlexList's
  690. linkage from that closest pointer to the newly requested node. 
  691. The current pointer is left positioned at the new node.  Please
  692. note that array, search/sort, and list functions interact in that
  693. they all work with and modify the current node setting.  Stack
  694. and queue functions are independent, however.
  695.  
  696.  
  697.                   FlexList Compaction Functions
  698.  
  699. Sometimes you want to work with a list, other times it's more
  700. convenient to work with an array.  Although FlexList allows this
  701. chameleon behavior, your application may progress in stages that
  702. favor a linked list at one point and a conventional C array at
  703. another.  FlexList has "compaction" functions for converting a
  704. conventional array into a FlexList or vice versa, thus allowing
  705. you to optimize the performance of your application.
  706.  
  707.  
  708.                FLunpack()          FLunpackNew()
  709.                FLpack()            FLpackPtrs()
  710.  
  711.  
  712. You can think of the FLunpack/FLunpackNew as exploding the
  713. conventional C array into a FlexList.  Think of the FLpack
  714. function as doing the exact opposite or imploding a FlexList into
  715. a conventional C array.  Arrays compacted by FLpack and
  716. FLpackPtrs must be explicitly deleted with a call to free when no longer needed if their memory is ever to be recovered for
  717. subsequent reuse.  FLpackPtrs  returns an array of void pointers
  718. pointing to the data in the FlexNodes.  This array is NULL
  719. terminated to facilitate subsequent processing.
  720.  
  721. For the last example program we'll clone a vector of char
  722. pointers but the clone will have the advantage over its parent of
  723. being sorted in alphabetical order.
  724.  
  725.  
  726.      #include  <stdio.h>      /*  printf()  */
  727.      #include  <stdlib.h>     /*  free()  */
  728.      #include  <string.h>     /*  strcmp()  */
  729.      #include  <flexlist.h>
  730.  
  731.      char *a[] = { "one", "two", "three", "four", "five" };
  732.      char **A;
  733.  
  734.      int strCmp(char **s, char **t)
  735.      {
  736.           return strcmp(*s,*t);
  737.      }
  738.  
  739.      main()
  740.      {
  741.           FlexList l;
  742.           int i;
  743.  
  744.           (void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
  745.                sizeof(a[0]),a);
  746.           (void) FLsort(&l,FLcomparE(strCmp));
  747.           A = FLpack(&l);
  748.           for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)
  749.                (void) printf("\n a[%d] = %s",i,a[i]);
  750.           if (A)  {
  751.                for (i = 0; i < FLnodes(&l); i++)
  752.                     (void) printf("\n A[%d] = %s",
  753.                          i,((char **)A)[i]);
  754.                free(A);
  755.           }
  756.           (void) FLclear(&l);
  757.           return 0;
  758.      }
  759.  
  760. Remember that the FlexNodes in this program contain char pointers
  761. and that the compare function is passed pointers to the char
  762. pointers, that is why the strCmp has to dereference them.
  763.  
  764. Many commercial C toolbox functions require vector parameters. 
  765. With FlexList's compaction functions you can manipulate vectors
  766. on the fly.  The vectors can be stored in files and loaded as
  767. needed via a FlexList and subsequent packing.  The vector can then be kept around only during the computation phase in which it
  768. is needed.  Large, oversized, static vectors need not be
  769. allocated at compile time to cope with worst case scenarios,
  770. thereby consuming precious data segment space within your
  771. program.
  772.  
  773.  
  774.                 Accessing FlexList Nodes and Data
  775.  
  776. Now that we've finished categorizing FlexList functions along the
  777. lines of its hybrid stack-queue-list-array structure, let's
  778. rethink what we've seen in terms of how the FlexList was
  779. accessed, namely: by value, by reference, and by node.  This
  780. gives us a second way to analyze FlexList functions.
  781.  
  782. "By value" implies that the data is copied to or from a FlexNode. 
  783. For example, with FLpopD the top node of the stack is popped and
  784. the data is copied to the address specified by the second
  785. parameter before the node is freed and returned to the heap.  We
  786. are in effect accessing the data in the top node by value since
  787. we are retrieving, in actuality, a copy of it.
  788.  
  789.           FLpopD(&s,&i);   /*  i is same type in FlexNode  */
  790.  
  791. "By reference" implies that the data in the FlexNode is accessed
  792. by pointer.  You will need to type cast these void pointers to
  793. pointers to the type of data you have stored in the FlexNodes. 
  794. Suppose we're walking backward across a FlexList of integers with
  795. the code:
  796.  
  797.           while ((iptr = FLprevD(&l,(void *)0)) != (int *)0)
  798.                (void) printf("\n  %d",*iptr);
  799.  
  800. All void pointers returned by FlexList functions point to user
  801. data.  Thus the data can be modified directly.  "By reference"
  802. functions are provided to speed up processing.  Without pointer
  803. access you would have to first copy the data out of the FlexNode,
  804. modify it and then copy it back.  With large data structures that
  805. could prove to be quite inefficient.  Please note the FLnextD and
  806. FLprevD are purely "by reference" when called with their second
  807. parameters equal to the NULL address.  Actually all FlexList
  808. functions returning void pointers allow access "by reference" in
  809. combination perhaps with "by value" access.
  810.  
  811. In queuing network simulations you will want to move nodes
  812. between FlexLists rapidly.  Without access "by node" you would
  813. have to "FLpopD" the source queue and "FLinsQD" the destination
  814. queue.  This would entail copying the data from the front node
  815. into a local variable of the same type, unlinking and
  816. deallocating the FlexNode, then reallocating a new FlexNode and
  817. linking it into the other queue and finally copying the data from
  818. the local variable back into the node.  The faster way is to unlink the FlexNode from the source queue and relink it directly
  819. into the destination queue, e.g.
  820.  
  821.           FLinsN(&dstQ,FLpopN(&srcQ));
  822.  
  823. If dstQ is already full then the node popped from srcQ is lost in
  824. the twilight zone.  A better approach would be to prevent the
  825. chance of FlexNodes being left dangling:
  826.  
  827.           while (FLnotFull(&dstQ) && FLnodes(&srcQ))
  828.                (void) FLinsN(&dstQ,FLpopN(&srcQ));
  829.  
  830. The "By node" functions unlink and relink FlexNodes directly
  831. between compatible FlexLists.  Compatible in this sense means
  832. that both FlexLists have equal sizeofNodeData fields (not
  833. necessarily initialized for the same data type) .  Use the
  834. FLsizeofNodeData function to read the sizeofNodeData field.  Two
  835. FlexLists could also be considered to be compatible if they are
  836. both variant FlexLists with compatible data.  I should point out
  837. that variant FlexLists have the sizeofNodeData fields set to
  838. zero.  Be careful not to assume that two FlexLists are compatible
  839. just because both sizeofNodeData fields are equal to zero.  You
  840. can use FLisVariant to retrieve the virtual function table
  841. pointer within the FlexList header.  If two variant FlexLists use
  842. the same virtual function table, they are most likely compatible. 
  843. You are responsible for insuring that your FlexLists are
  844. compatible.  Remember also, FlexNodes unlinked with a function
  845. ending with "N" must be relinked with a function ending with "N"
  846. to a compatible FlexList or otherwise explicitly disposed of.
  847.  
  848.  
  849.                              Summary
  850.  
  851. Let's review what we learned starting with the points to remember
  852. when programming with the FlexList tool.
  853.  
  854.      1.   Be sure to include the FlexList header in any module
  855.           that references FlexList functions.
  856.  
  857.      2.   Define your global, static, and local stacks, queues,
  858.           lists, etc. as "FlexList".  Define your dynamic
  859.           versions as pointers to FlexLists, i.e. "FlexL".
  860.  
  861.      3.   Construct your FlexList variable with a static
  862.           constructor function and your FlexList pointer with a
  863.           dynamic constructor function.
  864.  
  865.      4.   The first parameter of all FlexList functions, with the
  866.           exception of FLdelete, is an address of a FlexList, or
  867.           putting it another way, is a pointer to a FlexList.  If
  868.           the function is somehow involved with the copying of
  869.           user data, the address of the data is always passed in
  870.           the second parameter.
  871.  
  872.      5.   All FlexList functions return either pointers or
  873.           integers.  A returned value of zero indicates failure
  874.           of the function to complete its task.
  875.  
  876.      6.   Destruct all FlexLists when they are no longer needed. 
  877.           Use FLclear on global, static, or local FlexList
  878.           variables and FLdelete on dynamic FlexLists.
  879.  
  880.      7.   Link your application with the compiled flexlist object
  881.           module or the flexlist library you build.
  882.  
  883.  
  884. Next, let's review the various functions available in the
  885. FlexList tool.  FlexList functions can be categorized according
  886. to the logical nature of a FlexList's inherent hybrid stack-
  887. queue-list-array structure.
  888.  
  889.  
  890.             FlexList Constructor/Destructor Functions
  891.  
  892.      FLfixed()           FLunpack()          FLvariant()
  893.      FLstr()             FLclear()
  894.  
  895.      FLfixedNew()        FLunpackNew()       FLvariantNew()
  896.      FLstrNew()          FLdelete()
  897.  
  898.  
  899.                 FlexList Header Access Functions
  900.  
  901.      FLfrontD()          FLcurrentD()        FLrearD()
  902.      FLcurNum()          FLnodes()           FLmaxNodes()
  903.      FLsetMaxNodes()     FLnotFull()         FLsizeofNodeData()
  904.      FLisSorted()        FLunSort()          FLcompare()
  905.      FLsetCompare()      FLisFixed()         FLisVariant()
  906.      FLData()
  907.  
  908.  
  909.                FlexList Stack and Queue Functions
  910.  
  911.  
  912.      FLpushN()           FLpushD()           FLpopN()
  913.      FLpopD()            FLtopD()            FLinsQN()
  914.      FLinsQD()           FLfrontD()          FLrearD()
  915.  
  916.                      FlexList List Functions
  917.  
  918.      FLmkcur()           FLinsN()            FLinsD()
  919.      FLinsSortN()        FLinsSortD()        FLdelN()
  920.      FLdelD()            FLnextD()           FLprevD()
  921.      FLcurNum()          FLcurrentD()        FLcompare()
  922.      FLsetCompare()
  923.  
  924.  
  925.                  FlexList Search/Sort Functions
  926.  
  927.      FLinsSortN()        FLinsSortD()        FLfindFirstD()
  928.      FLfindNextD()       FLfindLastD()       FLfindPrevD()
  929.      FLsort()            FLisSorted()        FLunSort()
  930.      FLcompare()         FLsetCompare()
  931.  
  932.  
  933.                     FlexList Array Functions
  934.  
  935.      FLstoreD()          FLrecallD()         FLmkcur()
  936.      FLcurrentD()        FLcurNum()
  937.  
  938.  
  939.                   FlexList Compaction Functions
  940.  
  941.      FLunpack()          FLunpackNew()       FLpack()
  942.      FLpackPtrs()
  943.  
  944.  
  945. Finally, FlexLists can be accessed "by value", "by reference",
  946. and "by node."  "By value" entails the copying of user data
  947. between the FlexNodes and user specified addresses.  If the
  948. address specified is NULL than the copying of data is inhibited
  949. but the function performs otherwise as expected.  The address is
  950. always the second parameter of the FlexList function requiring
  951. it.  "By reference" infers that user data is manipulated directly
  952. inside a FlexNode via a pointer.  All FlexList functions
  953. returning void pointers allow "by reference" access.  "By node"
  954. functions allow FlexNodes to be yanked/inserted from/into
  955. FlexLists.  These functions are named with "N" suffixes.  Move
  956. FlexNodes only between compatible FlexLists.  Don't leave
  957. FlexNodes dangling: either insert them back into a compatible
  958. FlexList with an "N" function or explicitly free them.
  959.  
  960.  
  961. By now you should be ready to start the planning and subsequent
  962. coding of your FlexList application with the help of the
  963. reference chapter on FlexList functions.  Later, when you feel
  964. comfortable with FlexList, you will want to try your hand at
  965. deriving your own variant FlexLists (lists that contain heterogeneous data).  Be sure to read the entry for FLvariant in
  966. the reference chapter for an explanation of writing your own
  967. FlexList virtual functions that accommodate your heterogeneous
  968. data.  The FlexList dynamic constructor entries, i.e. constructor
  969. functions ending with "New", explain how to encapsulate your
  970. list-pertinent data within FlexList headers.
  971.  
  972. Chapter 3.   FlexList Reference
  973.  
  974.  
  975. This chapter contains a detailed specification of each FlexList
  976. function. 
  977.  
  978.  
  979. FLclear                  Static Destructor
  980.  
  981.  
  982. *    Summary
  983.  
  984.           #include <flexlist.h>
  985.  
  986.           int FLclear(FlexL L);
  987.  
  988. *    Description
  989.  
  990.           FLclear deletes all nodes in the FlexList.  With
  991.           variant FlexLists all nodes may not be able to be
  992.           destructed.
  993.  
  994. *    Return value
  995.  
  996.           FLclear returns zero if any nodes are left remaining or
  997.           if "L" is NULL, otherwise it returns 1.
  998.  
  999. *    See Also
  1000.  
  1001.           FLdelete
  1002.  
  1003. *    Example
  1004.  
  1005.           #include <stdio.h>       /*  printf() */
  1006.           #include <flexlist.h>
  1007.  
  1008.           int i[] = { 1, 2, 3, 4, 5 };
  1009.  
  1010.           main()
  1011.           {
  1012.                FlexList l;
  1013.  
  1014.                (void) FLunpack( &l, sizeof(i[0]), sizeof(i) /
  1015.                     sizeof(i[0]),i);
  1016.                (void) printf("\n nodes: %d",FLnodes(&l));
  1017.                (void) FLclear(&l);
  1018.                (void) printf("\n nodes: %d",FLnodes(&l));
  1019.                return 0;
  1020.           }
  1021. FLcompare               Header Access
  1022.  
  1023.  
  1024. *    Summary
  1025.  
  1026.           #include <flexlist.h>
  1027.  
  1028.           int (*FLcompare(FlexL L))
  1029.                (const void *D1, const void *D2);
  1030.  
  1031. *    Return value
  1032.  
  1033.           The FLcompare macro returns the pointer to the user
  1034.           defined compare function used in searches and sorts.
  1035.  
  1036. *    Remarks
  1037.  
  1038.           If you are sorting a FlexList on various keys at
  1039.           different times, it is convenient to know if the
  1040.           FlexList is sorted and on what key.  Use FLisSorted and
  1041.           FLcompare to determine this.
  1042.  
  1043. *    See also
  1044.  
  1045.           FLsetCompare, FLsort, FLisSorted, FLunSort
  1046.  
  1047. *    Example
  1048.  
  1049.           #include <stdio.h>       /*  printf()  */
  1050.           #include <flexlist.h>
  1051.  
  1052.           int a[] = { 1, 2, 3, 4, 5 };
  1053.  
  1054.           int intAscending(int *i1, int *i2)
  1055.           { return ((*i1 < *i2)? -1 : (*i1 > *i2)? 1 : 0); }
  1056.  
  1057.           int intDescending(int *i1, int *i2)
  1058.           { return ((*i1 < *i2)? 1 : (*i1 > *i2)? -1 : 0); }
  1059.  
  1060. FLcompare
  1061.  
  1062.  
  1063.           void countToFive(FlexL L)
  1064.           {
  1065.                if (FLcompare(L) == FLcomparE(intDescending))
  1066.                     for (FLmkcur(L,0);FLprevD(L,(void *)0);
  1067.                          /* no reinit */)
  1068.                          printf("\n%d",*(int *)FLcurrentD(L));
  1069.                else
  1070.                     for (FLmkcur(L,0);FLnextD(L,(void *)0);
  1071.                          /* no reinit */)
  1072.                          printf("\n%d",*(int *)FLcurrentD(L));
  1073.           }
  1074.  
  1075.           main()
  1076.           {
  1077.                FlexList l;
  1078.  
  1079.                FLunpack(&l,sizeof(a[0]),sizeof(a)/
  1080.                     sizeof(a[0]),a);
  1081.                FLsort(&l,FLcomparE(intDescending));
  1082.                countToFive(&l);
  1083.                FLsort(&l,FLcomparE(intAscending));
  1084.                countToFive(&l);
  1085.                FLclear(&l);
  1086.                return 0;
  1087.           }
  1088.  
  1089.           This program always prints the contents of the FlexList
  1090.           in ascending order by determining the sorted order and
  1091.           then either walking backward or forward across the
  1092.           FlexList to achieve an ascending order.
  1093.  
  1094.           The FLcomparE macro, defined in flexlist.h, is used to
  1095.           precisely type cast my compare function to the type
  1096.           required by FLsort and FLsetCompare.
  1097.  
  1098. FLcurNum                Header & List Access
  1099.  
  1100.  
  1101. *    Summary
  1102.  
  1103.           #include <flexlist.h>
  1104.  
  1105.           unsigned FLcurNum(FlexL L);
  1106.  
  1107. *    Return Value
  1108.  
  1109.           The FLcurNum macro returns the number of the current
  1110.           node in the FlexList.  If there is no current node set
  1111.           or "L" is NULL then zero is returned.
  1112.  
  1113. *    Remarks
  1114.  
  1115.           FlexNodes are numbered starting with one.  Whenever a
  1116.           FlexList is first constructed or cleared the current
  1117.           node is set to zero.
  1118.  
  1119. *    See Also
  1120.  
  1121.           FLcurrentD, FLmkcur
  1122.  
  1123. *    Example
  1124.  
  1125.           #include <flexlist.h>
  1126.  
  1127.           main()
  1128.           {
  1129.                FlexList l;
  1130.  
  1131.                FLstr(&l);               /*  FLcurNum(&l) == 0  */
  1132.                FLinsD(&l,"one");
  1133.                FLinsD(&l,"two");
  1134.                FLinsQD(&l,"three");     /*  FLcurNum(&l) == 2  */
  1135.                FLdelD(&l,(void *)0);    /*  FLcurNum(&l) == 1  */
  1136.                /*  list now contains: "one", "three"  */
  1137.                FLmkcur(&l,FLnodes(&l)); /*  FLcurNum(&l) == 2  */
  1138.                FLclear(&l);             /*  FLcurNum(&l) == 0  */
  1139.                return 0;
  1140.           }
  1141. FLcurrentD              Header & List Access
  1142.  
  1143.  
  1144. *    Summary
  1145.  
  1146.           #include <flexlist.h>
  1147.  
  1148.           void * FLcurrentD(FlexL L);
  1149.  
  1150. *    Return Value
  1151.  
  1152.           The FLcurrentD macro returns a pointer to the data area
  1153.           of the current node or NULL if there is no current
  1154.           node.
  1155.  
  1156. *    See Also
  1157.  
  1158.           FLfrontD, FLrearD, FLmkcur, FLnextD, FLprevD
  1159.  
  1160. *    Example
  1161.  
  1162.           #include <stdio.h>       /*  printf()  */
  1163.           #include <flexlist.h>
  1164.  
  1165.           main()         /*  count to three  */
  1166.           {
  1167.                FlexList l;
  1168.  
  1169.                FLstr(&l);
  1170.                FLinsQD(&l,"one");
  1171.                FLinsQD(&l,"two");
  1172.                FLinsQD(&l,"three");
  1173.                while (FLnextD(&l,(void *)0))
  1174.                     printf("\n%s",(char *)FLcurrentD(&l));
  1175.                FLclear(&l);
  1176.           }
  1177.  
  1178.           The current node remains set at zero until the "while
  1179.           loop."  FLcurrentD returns a pointer to each successive
  1180.           string until FLnextD reaches the end of the FlexList.
  1181. FLData                  Header Access
  1182.  
  1183.  
  1184. *    Summary
  1185.  
  1186.           #include <flexlist.h>
  1187.  
  1188.           void * FLData(FlexL L);
  1189.  
  1190. *    Return value
  1191.  
  1192.           The FLData macro returns a pointer to the beginning of
  1193.           the user data area within the FlexList.  The FlexList
  1194.           must have been constructed with FLfixedNew,
  1195.           FLunpackNew, FLvariantNew, or FLstrNew.  In other words
  1196.           it must be a dynamically allocated FlexList.  If L is
  1197.           NULL or it was not dynamically allocated then NULL is
  1198.           returned.
  1199.  
  1200. *    Remarks
  1201.  
  1202.           If your dynamic FlexList doesn't store data in the
  1203.           FlexList header, don't use the returned pointer to
  1204.           access data that isn't there.  In any case the pointer
  1205.           can be interpreted as a boolean value with true
  1206.           indicating that the FlexList was dynamically allocated. 
  1207.           A Flexlist doesn't maintain a sizeofLocalData field
  1208.           from which it can ascertain whether or not you store
  1209.           any data in the FlexList header.  Therefore FLData
  1210.           can't tell whether or not the header has been enlarged
  1211.           to accommodate your data.  It knows only that
  1212.           dynamically allocated headers can be enlarged to
  1213.           accommodate user data and static ones can't!  It simply
  1214.           returns a pointer to the end of usual FlexList data and
  1215.           the start of your data if any.  Leaving out a
  1216.           sizeofLocalData field in the header was a design trade
  1217.           off to save space. 
  1218.  
  1219. *    See also
  1220.  
  1221.           FLfixedNew, FLunpackNew, FLvariantNew
  1222.  
  1223. *    Example
  1224.  
  1225.           The FLfixedNew entry has an excellent example of using
  1226.           FLData to initialize and modify user data local to a
  1227.           FlexList.
  1228.  
  1229. FLdelD                  List Access
  1230.  
  1231.  
  1232. *    Summary
  1233.  
  1234.           #include <flexlist.h>
  1235.  
  1236.           int FLdelD(FlexL L, void *D);
  1237.  
  1238. *    Description
  1239.  
  1240.           Copies data from current node to specified location,
  1241.           i.e. "void *D", if any then deletes the current node
  1242.           making the previous node current.
  1243.  
  1244. *    Return Value
  1245.  
  1246.           Returns 1 if successful in deleting the current node,
  1247.           otherwise 0 is returned to indicate failure.
  1248.  
  1249. *    See Also
  1250.  
  1251.           FLdelN, FLinsD, FLinsN, FLpopD, FLpopN
  1252.  
  1253. *    Example
  1254.  
  1255.           #include <stdio.h>       /*  printf()  */
  1256.           #include <flexlist.h>
  1257.  
  1258.           int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  1259.  
  1260.           main()    /*  count down from ten  */
  1261.           {
  1262.                FlexList l;
  1263.                int i;
  1264.  
  1265.                FLunpack(&l,sizeof(a[0]),sizeof(a)/
  1266.                     sizeof(a[0]),a);
  1267.                FLmkcur(&l,FLnodes(&l));
  1268.                while (FLdelD(&l,&i))
  1269.                     printf("\n%d",i);
  1270.                return 0;
  1271.           }
  1272.  
  1273.           The program initializes a FlexList with an array of ten
  1274.           integers.  The last node in the list is made the
  1275.           current node.  Finally, the nodes are deleted from the
  1276.           rear towards the front and the contents of each node is
  1277.           displayed.
  1278.  
  1279. FLdelete                Dynamic Destructor
  1280.  
  1281.  
  1282. *    Summary
  1283.  
  1284.           #include <flexlist.h>
  1285.  
  1286.           int FLdelete(FlexL *Lptr);
  1287.  
  1288. *    Description
  1289.  
  1290.           Call FLdelete to destruct dynamically allocated
  1291.           FlexLists, i.e. those constructed by FLfixedNew,
  1292.           FLunpackNew, FLvariantNew, or FLstrNew.  FLdelete first
  1293.           calls the user specified FLDdestruct virtual function
  1294.           with the address of user's data in the FlexList header. 
  1295.           If the FLDdestruct function returns true then FLclear
  1296.           is called to destruct the FlexNodes.  If all FlexNodes
  1297.           are successfully destructed then the FlexList is freed
  1298.           and true returned.
  1299.  
  1300. *    Return value
  1301.  
  1302.           Returns non zero if the FlexList is deallocated.
  1303.  
  1304. *    Remarks
  1305.  
  1306.           FLdelete checks to see if the FlexList was dynamically
  1307.           allocated before proceeding.  If the FlexList is
  1308.           dynamically allocated the FLDdestruct pointer in the
  1309.           FlexList header will be something other than NULL.  If
  1310.           you need to determine if a FlexList was dynamically
  1311.           allocated call FLData; it returns true whenever the
  1312.           FlexList is dynamic.
  1313.  
  1314. *    See Also
  1315.  
  1316.           FLfixedNew, FLvariantNew, FLData, FLclear
  1317.  
  1318. *    Example
  1319.  
  1320.           See the example for the FLfixedNew entry.
  1321.            FLdelN        List Access
  1322.  
  1323.  
  1324. *    Summary
  1325.  
  1326.           #include <flexlist.h>
  1327.  
  1328.           FlexN  FLdelN(FlexL L);
  1329.  
  1330. *    Description
  1331.  
  1332.           Deletes the current node from the list, if any, by
  1333.           unlinking it and returning a pointer to it.  The
  1334.           previous node becomes the new current node.  If there
  1335.           is no previous node then the current node becomes
  1336.           undefined and curNum is 0.
  1337.  
  1338. *    Return Value
  1339.  
  1340.           FLdelN returns a pointer to the unlinked node or NULL
  1341.           if there is no current node to unlink.  Any unlinked
  1342.           node must be relinked into a FlexList with a FlexList
  1343.           function ending with "N" or otherwise explicitly freed!
  1344.  
  1345. *    See Also
  1346.  
  1347.           FLpopN, FLinsN, FLdelD, FLpushN, FLinsQN, FLinsSortN
  1348.  
  1349. *    Example
  1350.  
  1351.           #include <stdio.h>       /*  printf()  */
  1352.           #include <flexlist.h>
  1353.  
  1354.           int ints[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
  1355.  
  1356.           main()    /*  count down from ten  */
  1357.           {
  1358.                FlexList src, dst;
  1359.  
  1360.                FLunpack(&src,sizeof(int),sizeof(ints)/
  1361.                     sizeof(int),ints);
  1362.                FLfixed(&dst,sizeof(int));
  1363.                FLmkcur(&src,FLnodes(&src));
  1364.                while (FLnotFull(&dst) && FLnodes(&src))
  1365.                     FLinsN(&dst,FLdelN(&src));
  1366.                while (FLpopD(&dst,ints))
  1367.                     printf("\n%d",ints[0]);
  1368.                return 0;
  1369.           }
  1370. FLfindFirstD            List Access
  1371. FLfindLastD
  1372. FLfindNextD
  1373. FLfindPrevD
  1374.  
  1375.  
  1376. *    Summary
  1377.  
  1378.      #include <flexlist.h>
  1379.  
  1380.           void * FLfindFirstD (FlexL L, const void *D);
  1381.           void * FLfindLastD  (FlexL L, const void *D);
  1382.           void * FLfindNextD  (FlexL L, const void *D);
  1383.           void * FLfindPrevD  (FlexL L, const void *D);
  1384.  
  1385. *    Description
  1386.  
  1387.           The FLfind...D functions work regardless if the
  1388.           FlexList is sorted or not.  If it is sorted then the
  1389.           binary search algorithm is used to find the First/Last
  1390.           matching data and a linear search is used to find the
  1391.           Next/Prev match stopping immediately after the first
  1392.           mismatch.  If the FlexList is not sorted then the
  1393.           linear search algorithm is used to find the First/Last
  1394.           matching data and again to find the Next/Prev match
  1395.           stopping only at the ends of the list.
  1396.  
  1397. *    Return Value
  1398.  
  1399.           FLfind...D returns a pointer to the data in the
  1400.           FlexNode found to be a match.  If no match is found
  1401.           NULL is returned.
  1402.  
  1403. *    See Also
  1404.  
  1405.           FLsort, FLinsSortD, FLsetCompare
  1406.  
  1407. *    Example
  1408.  
  1409.           The example program first searches an unsorted list of
  1410.           integers.  The list is sorted and searched again.  Both
  1411.           forward and backward searches are employed.
  1412.  
  1413.           #include <stdio.h>       /*  printf()  */
  1414.           #include <stdlib.h>      /*  abs()  */
  1415.           #include <flexlist.h>
  1416.  
  1417.           #define MatchTolerance  5
  1418.  
  1419.           int ints[] = { 40, 70, 23, 5, 67, 2 ,10, 
  1420.                1 , 5, 3, 36, 27 };
  1421. FLfindFirstD
  1422. FLfindLastD
  1423. FLfindNextD
  1424. FLfindPrevD
  1425.  
  1426.  
  1427.           int intcmp(int *i1, int *i2)
  1428.                {  return (*i1 - *i2);  }
  1429.  
  1430.           int intmatch(int *i1, int *i2)
  1431.           {  
  1432.                if (abs(*i1 - *i2) < MatchTolerance)
  1433.                     return 0;
  1434.                return 1;
  1435.           }
  1436.  
  1437.           void search(FlexL L)
  1438.           {
  1439.                int i;
  1440.  
  1441.                FLsetCompare(L,FLcomparE(intmatch));
  1442.                for (i = 1; i <= 100; i += MatchTolerance)  {
  1443.                     printf("\n\nsearch forward for %d +/-%d.\n",
  1444.                          i, MatchTolerance);
  1445.                     if (FLfindFirstD(L,&i))
  1446.                          printf("\nnode: %3d    value: %3d",
  1447.                               FLcurNum(L),*(int *)FLcurrentD(L));
  1448.                     while (FLfindNextD(L,&i))
  1449.                          printf("\nnode: %3d    value: %3d",
  1450.                               FLcurNum(L),*(int *)FLcurrentD(L));
  1451.                     printf("\n\nsearch backward for %d"
  1452.                          " +/- %d.\n",i,MatchTolerance);
  1453.                     if (FLfindLastD(L,&i))
  1454.                          printf("\nnode: %3d    value: %3d",
  1455.                               FLcurNum(L),*(int *)FLcurrentD(L));
  1456.                     while (FLfindPrevD(L,&i))
  1457.                          printf("\nnode: %3d    value: %3d",
  1458.                               FLcurNum(L),*(int *)FLcurrentD(L));
  1459.                }
  1460.           }
  1461. FLfindFirstD
  1462. FLfindLastD
  1463. FLfindNextD
  1464. FLfindPrevD
  1465.  
  1466.  
  1467.           main()
  1468.           {
  1469.                FlexList l;
  1470.  
  1471.                FLunpack(&l,sizeof(int),sizeof(ints)/
  1472.                     sizeof(int),ints);
  1473.                search(&l);
  1474.                FLsort(&l,FLcomparE(intcmp));
  1475.                search(&l);
  1476.                FLclear(&l);
  1477.                return 0;
  1478.           }
  1479.  
  1480.  
  1481.           The FLcomparE macro, defined in flexlist.h, is used to
  1482.           precisely type cast my two compare function pointers,
  1483.           intmatch and intcmp, to the types required by
  1484.           FLsetCompare and FLsort respectively.
  1485. FLfixed                 Static Constructor
  1486.  
  1487.  
  1488. *    Summary
  1489.  
  1490.           #include <flexlist.h>
  1491.  
  1492.           FlexL FLfixed(FlexL L, size_t sizeofNodeData);
  1493.  
  1494. *    Description
  1495.  
  1496.           FLfixed initializes the FlexList pointed to by L to
  1497.           hold data the size of sizeofNodeData.  MaxNodes is set
  1498.           to FLmaxMaxNodes, the maximum allowed for any FlexList
  1499.           which is UINT_MAX (the largest value of an unsigned
  1500.           integer).
  1501.  
  1502.           The FlexList can subsequently be used to warehouse data
  1503.           of this size.
  1504.  
  1505. *    Return value
  1506.  
  1507.           If successful, FLfixed returns L otherwise it returns
  1508.           FlexL0 which is defined in flexlist.h as (FlexL) 0.
  1509.  
  1510. *    See Also
  1511.  
  1512.           FLfixedNew, FLunpack, FLunpackNew, FLvariant,
  1513.           FLvariantNew, FLstr, FLstrNew
  1514.  
  1515. *    Example
  1516.  
  1517.           #include <flexlist.h>
  1518.  
  1519.           main()         /* construct a list of floats  */
  1520.           {
  1521.                FlexList l;
  1522.                float f;
  1523.  
  1524.                if (!FLfixed(&l,sizeof(f)))
  1525.                     return 1;
  1526.                f = 3.5;
  1527.                FLpushD(&l,&f);
  1528.                ...
  1529.           }
  1530. FLfixedNew              Dynamic Constructor
  1531.  
  1532.  
  1533. *    Summary
  1534.  
  1535.           #include <flexlist.h>
  1536.  
  1537.           FlexL FLfixedNew(
  1538.                size_t sizeofNodeData,
  1539.                size_t sizeofLocalData,
  1540.                int (*FLDdestruct)(void *LD)
  1541.           );
  1542.  
  1543. *    Description
  1544.  
  1545.           FLfixedNew allocates and initializes a FlexList big
  1546.           enough to hold user data within the FlexList header. 
  1547.           MaxNodes is set to FLmaxMaxNodes, the maximum allowed
  1548.           for any FlexList which is UINT_MAX (the largest value
  1549.           of an unsigned integer).
  1550.  
  1551.           The FlexList can subsequently be used to warehouse data
  1552.           in the FlexNode of the size sizeofNodeData.  The
  1553.           FlexList header can warehouse data of the size
  1554.           sizeofLocalData.
  1555.  
  1556.           Use FLdelete to destruct dynamically allocated
  1557.           FlexLists.  FLdelete calls the user defined function
  1558.           FLDdestruct which is passed the address of user data in
  1559.           the FlexList header (the address is never NULL).  If
  1560.           your FLDdestruct function returns something other than
  1561.           zero, FLdelete will then call FLclear to destruct the
  1562.           FlexNodes and if that is successful, FLdelete then
  1563.           frees the dynamically allocated FlexList.  If your
  1564.           FLDdestruct function returns zero then FLdelete will
  1565.           return zero.
  1566.  
  1567. *    Return value
  1568.  
  1569.           If successful, FLfixedNew returns a pointer to a
  1570.           dynamically allocated FlexList, otherwise it returns
  1571.           FlexL0 which is defined in flexlist.h as (FlexL) 0.
  1572.  
  1573. *    Remarks
  1574.  
  1575.           If your dynamic FlexList doesn't need to store data in
  1576.           the FlexList header then pass zero to the
  1577.           sizeofLocalData parameter.
  1578. FLfixedNew
  1579.  
  1580.  
  1581.           If your application doesn't require a FLDdestruct
  1582.           function call FLfixedNew with the NULL pointer
  1583.           constant, FLDdestruct0, defined in flexlist.h.
  1584.  
  1585.           If your dynamic FlexList doesn't store data in the
  1586.           FlexList header, don't access data with FLData! 
  1587.           Likewise if you do specify a FLDdestruct function, be
  1588.           sure your function ignores the local data parameter
  1589.           passed to it!  A Flexlist doesn't maintain a
  1590.           sizeofLocalData field from which it can ascertain
  1591.           whether or not you store any data in the FlexList
  1592.           header.  This was a design consideration to save space
  1593.           in the header.
  1594.  
  1595.           Use FLData and FLisFixed to determine if a FlexList was
  1596.           constructed with FLfixedNew or FLunpackNew.  FLData
  1597.           returns true for dynamically allocated FlexLists.
  1598.  
  1599. *    See Also
  1600.  
  1601.           FLData, FLdelete, FLisFixed, FLfixed, FLunpack,
  1602.           FLvariant
  1603.  
  1604. *    Example
  1605.  
  1606.           This program builds a list of floats and then aliases
  1607.           it.  When FLdelete is called it won't destruct the
  1608.           FlexList until all references to it are destructed. 
  1609.           The link count is maintained in the header of the
  1610.           dynamically allocated FlexList.
  1611.  
  1612.  
  1613.           #include <stdio.h>       /*  printf()  */
  1614.           #include <flexlist.h>
  1615.  
  1616.           FlexL FLlinkInit(FlexL L)
  1617.           {
  1618.                int *links;
  1619.  
  1620.                if ((links = FLData(L)) != (int *) 0)
  1621.                     *links = 1;
  1622.                return L;
  1623.           }
  1624. FLfixedNew
  1625.  
  1626.  
  1627.           FlexL FLlink(FlexL L)
  1628.           {
  1629.                int *links;
  1630.  
  1631.                if ((links = FLData(L)) != (int *) 0)
  1632.                     ++*links;
  1633.                return L;
  1634.           }
  1635.  
  1636.           int FLunlinked(void *LD)
  1637.           {  /*  LD is never NULL!  */
  1638.                int *links = (int *) LD;
  1639.  
  1640.                if (--*links)
  1641.                     return 0;
  1642.                return 1;
  1643.           }
  1644.  
  1645.           main()
  1646.           {
  1647.                FlexL L1, L2;
  1648.                float f;
  1649.  
  1650.                if ((L1 = FLlinkInit(FLfixedNew(sizeof(f),
  1651.                     sizeof(int),FLunlinked))) == FlexL0)
  1652.                     return 1;
  1653.                f = 3.5;
  1654.                FLpushD(L1,&f);
  1655.                f = 7.9;
  1656.                FLinsQD(L1,&f);
  1657.                L2 = FLlink(L1);
  1658.                f = 10.1;
  1659.                FLinsD(L2,&f);
  1660.                for (FLmkcur(L1,0); FLnextD(L1,&f);
  1661.                     /* no reinit */)
  1662.                     printf("\n%f",f);
  1663. FLfixedNew
  1664.  
  1665.  
  1666.                FLdelete(&L1);  /*  FLdelete fails!  */
  1667.                printf("\n nodes in L1: %u",FLnodes(L1));
  1668.                /*  three nodes in L2 */
  1669.                printf("\n nodes in L2: %u",FLnodes(L2));
  1670.                while (FLnextD(L2,&f))
  1671.                     printf("\n%f",f);
  1672.                FLdelete(&L2);  /*  FLdelete succeeds!  */
  1673.                /*  FlexList is gone!  */
  1674.                L1 = FlexL0;
  1675.                printf("\n nodes in L1: %u",FLnodes(L1));
  1676.                printf("\n nodes in L2: %u",FLnodes(L2));
  1677.                return 0;
  1678.           }
  1679.  
  1680.  
  1681.           The important thing to remember is that FLdelete calls
  1682.           your FLDdestruct function which must return true before
  1683.           FLdelete will destruct the FlexList.
  1684.  
  1685.           You must be careful with alias FlexList pointers.  When
  1686.           FLdelete was called with L1 it don't known that L1 is
  1687.           an alias for L2 and vice versa.  Neither does it know
  1688.           the scheme of your FLDdestruct function.  All FLdelete
  1689.           knows is that your FLDdestruct function said the
  1690.           FlexList can't be destructed at this time.
  1691. FLfrontD                Header, Stack, Queue, & List Access
  1692.  
  1693.  
  1694. *    Summary
  1695.  
  1696.           #include <flexlist.h>
  1697.  
  1698.           void * FLfrontD(FlexL L);
  1699.  
  1700. *    Return Value
  1701.  
  1702.           The FLfrontD macro returns a pointer to the data area
  1703.           of the first node in the list.  If there are no nodes
  1704.           in the list then NULL, i.e. (void *) 0 is returned.
  1705.  
  1706. *    See Also
  1707.  
  1708.           FLtopD, FLcurrentD, FLrearD, FLmkcur
  1709.  
  1710. *    Example
  1711.  
  1712.           #include <stdio.h>       /*  printf()  */
  1713.           #include <flexlist.h>
  1714.  
  1715.           int ints[] = { 1, 2, 3, 4, 5 };
  1716.  
  1717.           main()
  1718.           {
  1719.                FlexList i;
  1720.  
  1721.                FLunpack(&i,sizeof(ints[0]),sizeof(ints)/
  1722.                     sizeof(ints[0]),ints);
  1723.                while (*(int *)FLfrontD(&i) != 5)  
  1724.                     FLinsQN(&i,FLpopN(&i));  /* roll down */
  1725.                while (FLnodes(&i))  {
  1726.                     printf("\n%d", *(int *)FLfrontD(&I));
  1727.                     FLpopD(&i,(void *)0);  /* trash top node */
  1728.                }
  1729.                FLclear(&i);
  1730.                return 0;
  1731.           }
  1732.  
  1733.           This program initializes a FlexList with 5 nodes.  It
  1734.           then "rolls down the stack" until the top node contains
  1735.           5.  It then proceeds to dump and display the stack.
  1736.  
  1737. FLinsD                  List Access
  1738.  
  1739.  
  1740. *    Summary
  1741.  
  1742.           #include <flexlist.h>
  1743.  
  1744.           void * FLinsD(FlexL L, const void *D);
  1745.  
  1746. *    Description
  1747.  
  1748.           Inserts a new node after current node and copies the
  1749.           data, if specified, to the new node.  If D is NULL and
  1750.           the FlexList is variant, FLinsD can't allocate a new
  1751.           FlexNode since it doesn't know how big to make it.
  1752.  
  1753.           The newly inserted node becomes the new current node. 
  1754.           If current is undefined prior to the call then the new
  1755.           node is inserted at the front of the list.
  1756.  
  1757. *    Return Value
  1758.  
  1759.           Returns a pointer to the data area of the newly
  1760.           inserted node.  NULL is returned if the function fails.
  1761.  
  1762. *    See Also
  1763.  
  1764.           FLinsQD, FLinsSortD, FLpushD,  FLdelD, FLinsN
  1765.  
  1766. *    Example
  1767.  
  1768.           #include <stdio.h>       /*  printf()  */
  1769.           #include <flexlist.h>
  1770.  
  1771.           main()    /*  count backwards from ten  */
  1772.           {
  1773.                FlexList l;
  1774.                int i;
  1775.  
  1776.                FLfixed(&l,sizeof(int));
  1777.                for (i = 1; i <= 10; i++)
  1778.                     FLinsD(&l,&i);
  1779.                while (FLdelD(&l,&i))
  1780.                     printf("\n%d",i);
  1781.                return 0;
  1782.           }
  1783. FLinsN                  List Access
  1784.  
  1785.  
  1786. *    Summary
  1787.  
  1788.           #include <flexlist.h>
  1789.  
  1790.           void * FLinsN(FlexL N, FlexN N);
  1791.  
  1792. *    Description
  1793.  
  1794.           Inserts the given FlexNode into the FlexList after the
  1795.           current node.  This node becomes the new current node. 
  1796.           If current is undefined then the node is inserted at
  1797.           the front of the list.
  1798.  
  1799. *    Return Value
  1800.  
  1801.           Returns a pointer to the data area of the newly
  1802.           inserted node.  If the operation fails then NULL is
  1803.           returned.
  1804.  
  1805. *    See Also
  1806.  
  1807.           FLdelN, FLpopN, FLinsQN, FLinsSortN, FLpushN, FLinsD
  1808.  
  1809. *    Example
  1810.  
  1811.           #include <stdio.h>       /*  printf()  */
  1812.           #include <flexlist.h>
  1813.  
  1814.           int ints[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
  1815.  
  1816.           main()
  1817.           {
  1818.                FlexList src, dst;
  1819.                int i;
  1820.  
  1821.                FLunpack(&src,sizeof(int),sizeof(ints)/
  1822.                     sizeof(int),ints);
  1823.                FLfixed(&dst,sizeof(int));
  1824.                FLmkcur(&src,FLnodes(&src));
  1825.                while (FLnotFull(&dst) && FLnodes(&src))
  1826.                     FLinsN(&dst,FLdelN(&src));
  1827.                while (FLpopD(&dst,ints)
  1828.                     printf("\n%d",ints[0]);
  1829.                return 0;
  1830.           }
  1831. FLinsQD                 Queue Access
  1832.  
  1833.  
  1834. *    Summary
  1835.  
  1836.           #include <flexlist.h>
  1837.  
  1838.           void * FLinsQD(FlexL L, const void *D);
  1839.  
  1840. *    Description
  1841.  
  1842.           Queues a FlexNode onto the end of the FlexList.  Copies
  1843.           the data, if specified, to the new node.  If D is NULL
  1844.           and the FlexList is variant, FLinsQD can't allocate a
  1845.           new FlexNode since it doesn't know how big to make it.
  1846.  
  1847. *    Return Value
  1848.  
  1849.           Returns a pointer to the data area of the new node.  If
  1850.           operation fails it returns NULL.
  1851.  
  1852. *    See Also
  1853.  
  1854.           FLinsD, FLinsSortD, FLpushD, FLinsQN
  1855.  
  1856. *    Example
  1857.  
  1858.           #include <stdio.h>       /*  printf()  */
  1859.           #include <flexlist.h>
  1860.      
  1861.           main()
  1862.           {
  1863.                FlexList q;
  1864.                int i;
  1865.  
  1866.                FLfixed(&q,sizeof(i));
  1867.                for (i = 1; i <= 10; i++)
  1868.                     FLinsQD(&q,&i);
  1869.                while (FLpopD(&q,&i))
  1870.                     printf("\n%d",i);
  1871.           }
  1872.  
  1873.      The program queues the integers 1 to 10 and the removes them
  1874.      one by one from the queue, displaying them.
  1875.  
  1876. FLinsQN                 Queue Access
  1877.  
  1878.  
  1879. *    Summary
  1880.  
  1881.           #include <flexlist.h>
  1882.  
  1883.           void * FLinsQN(FlexL L, FlexN N);
  1884.  
  1885. *    Description
  1886.  
  1887.           Queues the given FlexNode onto the end of the FlexList.
  1888.  
  1889. *    Return Value
  1890.  
  1891.           Returns a pointer to the data area of the queued node. 
  1892.           If the operation fails it returns NULL.
  1893.  
  1894. *    See Also
  1895.  
  1896.           FLinsQD, FLinsN, FLinsSortN, FLpushN
  1897.  
  1898. *    Example
  1899.  
  1900.           #include <stdio.h>       /*  printf()  */
  1901.           #include <flexlist.h>
  1902.  
  1903.           int ints[] = { 1, 2, 3, 4, 5 };
  1904.  
  1905.           main()
  1906.           {
  1907.                FlexList i;
  1908.  
  1909.                FLunpack(&i,(sizeof(ints[0]),sizeof(ints)/
  1910.                     sizeof(ints[0]),ints);
  1911.                while (*(int *)FLfrontD(&i) != 5)
  1912.                     FLinsQN(&i,FLpopN(&i));
  1913.                while (FLnodes(&i))  {
  1914.                     printf("\n%d",*(int *)FLfrontD(&i));
  1915.                     FLpopD(&i,(void *)0);
  1916.                }
  1917.                FLclear(&i);
  1918.                return 0;
  1919.           }
  1920.  
  1921.           The program initializes a FlexList with 5 nodes
  1922.           containing the integers 1 through 5.  The "stack" is
  1923.           then rolled down until 5 is at the top of the stack. 
  1924.           The nodes are then displayed and discarded: 5, 1, 2, 3,
  1925.           4.
  1926. FLinsSortD              List Access
  1927.  
  1928.  
  1929. *    Summary
  1930.  
  1931.           #include <flexlist.h>
  1932.  
  1933.           void * FLinsSortD(FlexL L, const void *D);
  1934.  
  1935. *    Description
  1936.  
  1937.           Inserts data into the FlexList in sorted order.  The
  1938.           compare function, previously set by FLsetCompare or
  1939.           FLsort, specifies the order to insert by returning -1,
  1940.           0, or 1 indicating that the data in the node under test
  1941.           is less than, equal to, or greater than the data being
  1942.           inserted respectively.
  1943.  
  1944.           FLsort is called automatically prior to the insertion
  1945.           if the list is not in the sorted order specified by the
  1946.           compare function.
  1947.  
  1948.           Note that different compare functions will result in
  1949.           different sorted orders since the compare function can
  1950.           be written to test different fields of the data.  When
  1951.           several nodes each contain data that is equal to the
  1952.           data being inserted, the new data is inserted after the
  1953.           last of those nodes.  The addresses passed to the
  1954.           compare function point to the whole data areas.  The
  1955.           compare function must apply the test to the appropriate
  1956.           fields in these data areas.  These data areas are
  1957.           assumed to be the same type as that which the FlexList
  1958.           was constructed for.
  1959.  
  1960.           If D is NULL the insertion is aborted.
  1961.  
  1962.           The binary search algorithm is employed to find the
  1963.           location to insert the new node.  The inserted node
  1964.           becomes the new current node.
  1965.  
  1966. *    Return Value
  1967.  
  1968.           Returns a pointer to the data area of the newly
  1969.           inserted node.  Returns NULL if the operation fails.
  1970.  
  1971. *    See Also
  1972.  
  1973.           FLsort, FLfind...D, FLinsSortN
  1974. FLinsSortD
  1975.  
  1976.  
  1977. *    Example
  1978.  
  1979.           #include <stdio.h>       /*  printf()  */
  1980.           #include <string.h>      /*  strcmp()  */
  1981.           #include <flexlist.h>
  1982.  
  1983.           char *greetings[] = {  "hello",  "goodbye", 
  1984.                "hi", "bye", "hey there", 0 };
  1985.  
  1986.           main()
  1987.           {
  1988.                FlexList l;
  1989.                char buf[80];
  1990.                int i;
  1991.  
  1992.                FLstr(&l);
  1993.                FLsetCompare(&l,FLcomparE(strcmp));
  1994.                for (i = 0; greetings[i]; i++)
  1995.                     FLinsSortD(&l,greetings[i]);
  1996.                while (FLpopD(&l,buf))
  1997.                     printf("\n%s",buf);
  1998.                FLclear(&l)
  1999.                return 0;
  2000.           }
  2001.  
  2002.  
  2003.           This program first builds a FlexList of sorted greeting
  2004.           strings.  The FLcomparE macro, defined in flexlist.h,
  2005.           precisely type casts strcmp to the type required by
  2006.           FLsetCompare.
  2007. FLinsSortN              List Access
  2008.  
  2009.  
  2010. *    Summary
  2011.  
  2012.           #include <flexlist.h>
  2013.  
  2014.           void * FLinsSortN(FlexL L, FlexN N);
  2015.  
  2016. *    Description
  2017.  
  2018.           Inserts node into the FlexList in sorted order.  The
  2019.           compare function, previously set by FLsetCompare or
  2020.           FLsort, specifies the order to insert by returning -1,
  2021.           0, or 1 indicating that the data in the node under test
  2022.           is less than, equal to, or greater than the data in the
  2023.           node being inserted respectively.
  2024.  
  2025.           FLsort is called automatically prior to the insertion
  2026.           if the list is not in the sorted order specified by the
  2027.           compare function.
  2028.  
  2029.           Note that different compare functions will result in
  2030.           different sorted orders since the compare function can
  2031.           be written to test different fields of the data.  When
  2032.           several nodes each contain data that is equal to the
  2033.           data being inserted, the new node is inserted after
  2034.           last of those nodes.  The addresses passed to the
  2035.           compare function point to the whole data areas.  The
  2036.           compare function must apply the test to the appropriate
  2037.           fields in these data areas.  These data areas are
  2038.           assumed to be the same type as that which the FlexList
  2039.           was constructed for.
  2040.  
  2041.           The binary search algorithm is employed to find the
  2042.           location to insert the new node.  The inserted node
  2043.           becomes the new current node.
  2044.  
  2045. *    Return Value
  2046.  
  2047.           Returns a pointer to the data area of the newly
  2048.           inserted node.  Returns NULL if the operation fails.
  2049.  
  2050. *    See Also
  2051.  
  2052.           FLsort, FLfind...D, FLinsSortD
  2053. FLinsSortN
  2054.  
  2055.  
  2056. *    Example
  2057.  
  2058.           #include <stdio.h>       /*  printf()  */
  2059.           #include <string.h>      /*  strcmp()  */
  2060.           #include <flexlist.h>
  2061.  
  2062.           char *greetings[] = {  "hello",  "goodbye", 
  2063.                "hi", "bye", "hey there", 0 };
  2064.           
  2065.           main()
  2066.           {
  2067.                FlexList src, dst;
  2068.                FlexN N;
  2069.                int i;
  2070.  
  2071.                FLstr(&src);
  2072.                for (i = 0; greetings[i]; i++)
  2073.                     FLinsQD(&src,greetings[i]);
  2074.                FLstr(&dst);
  2075.                FLsetCompare(&dst,FLcomparE(strcmp));
  2076.                while (FLnotFull(&dst) && FLnodes(&src))
  2077.                     FLinsSortN(&dst,FLpopN(&src));
  2078.                while (FLnodes(&dst))  {
  2079.                     printf("\n%s",(char *)FLfrontD(&dst));
  2080.                     N = FLpopN(&dst);
  2081.                     free(N);
  2082.                }
  2083.                FLclear(&src); FLclear(&dst);
  2084.                return 0;
  2085.           }
  2086.  
  2087.           This program first builds a FlexList of greeting
  2088.           strings.  It then sorts the list by building a new list
  2089.           while performing an insertion sort.  Lastly, it
  2090.           displays the sorted strings.
  2091.  
  2092.           The FLcomparE macro, defined in flexlist.h, precisely
  2093.           type casts strcmp to the type required by FLsetCompare
  2094.           (and FLsort).
  2095. FLisFixed               Header Access
  2096.  
  2097.  
  2098. *    Summary
  2099.  
  2100.           #include <flexlist.h>
  2101.  
  2102.           unsigned FLisFixed(FlexL L);
  2103.  
  2104. *    Return value
  2105.  
  2106.           The FLisFixed macro returns true if the FlexList was
  2107.           constructed with FLfixed, FLfixedNew, FLunpack, or
  2108.           FLunpackNew.
  2109.  
  2110. *    Remarks
  2111.  
  2112.           FLisFixed and FLsizeofNodeData are identical.
  2113.  
  2114. *    See also
  2115.  
  2116.           FLsizeofNodeData
  2117.  
  2118. *    Example
  2119.  
  2120.           See FLsizeofNodeData example.
  2121. FLisSorted              Header Access
  2122.  
  2123.  
  2124. *    Summary
  2125.  
  2126.           #include <flexlist.h>
  2127.  
  2128.           int FLisSorted(FlexL L);
  2129.  
  2130. *    Return value
  2131.  
  2132.           The FLisSorted macro returns true if no FlexList
  2133.           functions have been called that could have ruined the
  2134.           sorted order of the FlexList from the last sort.
  2135.  
  2136. *    Remarks
  2137.  
  2138.           Be careful,  you can access data in FlexNodes via
  2139.           FLnextD, FLprevD, and FLmkcur without FLisSorted being
  2140.           able to detect a ruined sort.  If you modify keys in
  2141.           the data in this manner be sure to call FLunSort to let
  2142.           the FlexList know it is definitely unsorted.
  2143.  
  2144. *    See also
  2145.  
  2146.           FLunSort, FLsort, FLsetCompare
  2147.  
  2148. *    Example
  2149.  
  2150.           #include <flexlist.h>
  2151.  
  2152.           int a[] = { 1, 2, 3, 4, 5 };
  2153.  
  2154.           int intCompare(int *i1, int *i2)
  2155.           { return ((*i1 < *i2)? -1 : (*i1 > *i2)? 1 : 0); }
  2156.  
  2157.           main()
  2158.           {
  2159.                FlexL L;
  2160.  
  2161.                if ((L = FLunpackNew(sizeof(a[0]),sizeof(a)/
  2162.                     sizeof(a[0]),a)) == FlexL0)
  2163.                     return 1;
  2164.                /*  FLisSorted(L) is false  */
  2165.                FLsort(L,FLcomparE(intCompare));
  2166.                /*  FLisSorted(L) is true  */
  2167.                FLpushD(L,a);
  2168.                /*  FLisSorted(L) is false */
  2169.                FLdelete(&L);
  2170.           }         
  2171. FLisVariant             Header Access
  2172.  
  2173.  
  2174. *    Summary
  2175.  
  2176.           #include <flexlist.h>
  2177.  
  2178.           FlexNVFT FLisVariant(FlexL L);
  2179.  
  2180. *    Return value
  2181.  
  2182.           The FLisVariant macro returns true if the FlexList was
  2183.           constructed with FLvariant, FLvariantNew, FLstr, or
  2184.           FLstrNew.
  2185.  
  2186.           Actually FLisVariant returns the virtual function table
  2187.           pointer.  The virtual function table pointer is NULL
  2188.           for non variant FlexLists.  FlexNVFT0 is the NULL
  2189.           pointer constant defined in flexlist.h
  2190.  
  2191. *    See also
  2192.  
  2193.           FLisFixed, FLsizeofNodeData
  2194.  
  2195. *    Example
  2196.  
  2197.           #include <flexlist.h>
  2198.  
  2199.           main()
  2200.           {
  2201.                FlexList s, q;
  2202.  
  2203.                FLstr(&s); 
  2204.                FLstr(&q);
  2205.                FLinsQD(&s,"Now is not the");
  2206.                FLinsQD(&s,"time for wasting time");
  2207.                if (FLisVariant(&s) == FLisVariant(&q) &&
  2208.                     FLisVariant(&s) != FlexNVFT0)
  2209.                     FLinsQN(&q,FLpopN(&s));
  2210.                FLclear(&s);
  2211.                FLclear(&q);
  2212.           }
  2213.  
  2214.           The FlexLists are tested to see if they are compatible
  2215.           and variant before swapping nodes.
  2216. FLmaxNodes              Header Access
  2217.  
  2218.  
  2219. *    Summary
  2220.  
  2221.           #include <flexlist.h>
  2222.  
  2223.           unsigned FLmaxNodes(FlexL L);
  2224.  
  2225. *    Description
  2226.  
  2227.           The FLmaxNodes macro returns the maximum number of
  2228.           nodes allowed in the FlexList.  FLmaxMaxNodes is the
  2229.           maximum number of FlexNodes allowed in any FlexList and
  2230.           is defined in flexlist.h.
  2231.  
  2232. *    See Also
  2233.  
  2234.           FLsetMaxNodes, FLnodes, FLnotFull
  2235.  
  2236. *    Example
  2237.  
  2238.           #include <stdio.h>       /*  printf()  */
  2239.           #include <flexlist.h>
  2240.  
  2241.           main()
  2242.           {    
  2243.                FlexList q;
  2244.                int i = 1;
  2245.  
  2246.                FLfixed(&q,sizeof(int));
  2247.                printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
  2248.                printf("\n  - Vacancies: %u",FLnotFull(&q));
  2249.                printf("\n  = FlexNodes: %u",FLnodes(&q));
  2250.                FLsetMaxNodes(&q,35);
  2251.                FLinsQD(&q,&i);
  2252.                printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
  2253.                printf("\n  - Vacancies: %u",FLnotFull(&q));
  2254.                printf("\n  = FlexNodes: %u",FLnodes(&q));
  2255.                FLclear(&q);
  2256.                return 0;
  2257.           }
  2258.  
  2259.      This program limits a queue for integers to a maximum of 35.
  2260. FLmkcur                 List & Array Access
  2261.  
  2262.  
  2263. *    Summary
  2264.  
  2265.           #include <flexlist.h>
  2266.  
  2267.           void * FLmkcur(FlexL L, unsigned n);
  2268.  
  2269. *    Description
  2270.  
  2271.           Makes the requested node current.  Nodes in a FlexList
  2272.           are numbered starting at 1.  If the requested node is
  2273.           outside the range of the list then the current node
  2274.           becomes undefined and curNum is set to 0.  It is common
  2275.           practice to call FLmkcur requesting node 0 in order to
  2276.           set the current node as undefined.  The list is then
  2277.           ready for processing with the FLnextD or FLprevD
  2278.           function.
  2279.  
  2280. *    Return Value
  2281.  
  2282.           FLmkcur returns a pointer to the data area of the new
  2283.           current node.  If current is undefined, FLmkcur returns
  2284.           NULL.
  2285.  
  2286. *    See Also
  2287.  
  2288.           FLstoreD, FLrecallD, FLnextD, FLprevD, FLcurrentD
  2289.  
  2290. *    Example
  2291.  
  2292.           #include <stdio.h>       /*  printf()  */
  2293.           #include <flexlist.h>
  2294.  
  2295.           char *txt[] = { "Now is the time", 
  2296.                "for all smarter working",
  2297.                "programmers to spring for", "FlexList!" };
  2298.  
  2299.           main()    /* walk the list without FLnextD  */
  2300.           {
  2301.                FlexList l;
  2302.                char **c;
  2303.  
  2304.                FLunpack(&l,sizeof(txt[0]),sizeof(txt)/
  2305.                     sizeof(txt[0]),txt);
  2306.                while ((c = FLmkcur(&l,FLcurNum(&l)+1)) 
  2307.                     != (char **) 0)
  2308.                     printf("\n%s",*c);
  2309.           }
  2310. FLnextD                 List Access
  2311.  
  2312.  
  2313. *    Summary
  2314.  
  2315.           #include <flexlist.h>
  2316.  
  2317.           void * FLnextD(FlexL L, void *D);
  2318.  
  2319. *    Description
  2320.  
  2321.           FLnextD makes the next node in the list current.  If D
  2322.           is not NULL, the new current node's data is copied to
  2323.           the address specified by D.  If there is no next node,
  2324.           current becomes undefined and curNum is set to 0.
  2325.  
  2326. *    Return Value
  2327.  
  2328.           FLnextD returns a pointer to the data area of the next
  2329.           node.  If there is no next node, NULL is returned.
  2330.  
  2331. *    See Also
  2332.  
  2333.           FLprevD, FLmkcur, FLrecallD, FLstoreD
  2334.  
  2335. *    Example
  2336.  
  2337.           #include <stdio.h>       /*  printf()  */
  2338.           #include <flexlist.h>
  2339.  
  2340.           char *txt[] = { "Now is the time", 
  2341.                "for all smarter working",
  2342.                "programmers to spring for",
  2343.                "FlexList!", 0 };
  2344.  
  2345.           main()  /*  display the strings of txt[]  */
  2346.           {
  2347.                FlexList l;
  2348.                char buf[80];
  2349.                int i;
  2350.  
  2351.                FLstr(&l);
  2352.                for (i = 0; txt[i]; i++)
  2353.                     FLinsQD(&l,txt[i]);
  2354.                while (FLnextD(&l,buf))
  2355.                     printf("\n%s",buf);
  2356.                FLclear(&l);
  2357.                return 0;
  2358.           } FLnodes      Header Access
  2359.  
  2360.  
  2361. *    Summary
  2362.  
  2363.           #include <flexlist.h>
  2364.  
  2365.           unsigned FLnodes(FlexL L);
  2366.  
  2367.  
  2368. *    Return Value
  2369.  
  2370.           The FLnodes macro returns the number of nodes in the
  2371.           FlexList.
  2372.  
  2373. *    See Also
  2374.  
  2375.           FLmaxNodes, FLnotFull
  2376.  
  2377. *    Example
  2378.  
  2379.           #include <stdio.h>       /*  printf()  */
  2380.           #include <flexlist.h>
  2381.  
  2382.           char *txt[] = { "Now is the time", 
  2383.                "for all smarter working",
  2384.                "programmers to spring for",
  2385.                "FlexList!" };
  2386.  
  2387.           main()
  2388.           {
  2389.                FlexList l;
  2390.                char *c;
  2391.  
  2392.                FLunpack(&l,sizeof(txt[0]),sizeof(txt)/
  2393.                     sizeof(txt[0]),txt);
  2394.                while (FLnodes(&l))  {
  2395.                     FLpopD(&l,&c);
  2396.                     printf("\n%s",c);
  2397.                }
  2398.                FLclear(&l);
  2399.                return 0;
  2400.           }
  2401.  
  2402.           The program initializes the FlexList with FlexNodes
  2403.           containing pointers to all the strings of the txt
  2404.           array.  Pointers to the strings are popped and the
  2405.           strings displayed.
  2406. FLnotFull               Header Access
  2407.  
  2408.  
  2409. *    Summary
  2410.  
  2411.           #include <flexlist.h>
  2412.  
  2413.           unsigned FLnotFull(FlexL L);
  2414.  
  2415. *    Return Value
  2416.  
  2417.           The FLnotFull macro returns the number of nodes that
  2418.           can still be put into the FlexList.  If a FlexList is
  2419.           full then FLnotFull returns zero which is interpreted
  2420.           as false, in other words a FlexList that is not
  2421.           FLnotFull, is full!
  2422.  
  2423. *    See Also
  2424.  
  2425.           FLnodes, FLmaxNodes, FLsetMaxNodes
  2426.  
  2427. *    Example
  2428.  
  2429.           #include <stdio.h>       /*  printf()  */
  2430.           #include <flexlist.h>
  2431.  
  2432.           main()
  2433.           {    
  2434.                FlexList q;
  2435.                int i = 1;
  2436.  
  2437.                FLfixed(&q,sizeof(int));
  2438.                printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
  2439.                printf("\n  - Vacancies: %u",FLnotFull(&q));
  2440.                printf("\n  = FlexNodes: %u",FLnodes(&q));
  2441.                FLsetMaxNodes(&q,35);
  2442.                FLinsQD(&q,&i);
  2443.                printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
  2444.                printf("\n  - Vacancies: %u",FLnotFull(&q));
  2445.                printf("\n  = FlexNodes: %u",FLnodes(&q));
  2446.                FLclear(&q);
  2447.                return 0;
  2448.           }
  2449. FLpack                  Compaction
  2450.  
  2451.  
  2452. *    Summary
  2453.  
  2454.           #include <flexlist.h>
  2455.  
  2456.           void * FLpack(FlexL L);
  2457.  
  2458. *    Return Value
  2459.  
  2460.           FLpack returns the address of an array containing
  2461.           copies of the data in the all the FlexNodes in the
  2462.           FlexList.  If memory is unavailable or there are no
  2463.           nodes in the FlexList then FLpack returns NULL.  The
  2464.           array pointer must be type casted to a pointer to the
  2465.           type of data being stored in the FlexList.  When you
  2466.           are finished with the array it must be explicitly freed
  2467.           to return its memory to the heap.
  2468.  
  2469. *    See Also
  2470.  
  2471.           FLpackPtrs, FLunpack, FLunpackNew
  2472.  
  2473. *    Remarks
  2474.  
  2475.           Variant FlexLists can't be packed into a conventional C
  2476.           array since the FlexNodes are variant length.  FLpack
  2477.           always returns NULL for variant FlexLists.
  2478.  
  2479. *    Example
  2480.  
  2481.           #include <stdio.h>       /*  printf()  */
  2482.           #include <stdlib.h>      /*  free()  */
  2483.           #include <flexlist.h>
  2484.  
  2485.           int ints[] = { 40, 70, 23, 5, 67, 2 ,10, 
  2486.                1 , 5, 3, 36, 27 };
  2487.  
  2488.           int intcmp(int *i1, int *i2)
  2489.                {  return (*i1 - *i2);  }
  2490. FLpack
  2491.  
  2492.  
  2493.           main()
  2494.           {
  2495.                FlexList l;
  2496.                int *intsSorted, i;
  2497.  
  2498.                FLunpack(&l,sizeof(int),sizeof(ints)/
  2499.                     sizeof(int),ints);
  2500.                FLsort(&l,FLcomparE(intcmp));
  2501.                if ((intsSorted = FLpack(&l)) != (int *) 0)  {
  2502.                     for (i = 0; i < sizeof(ints)/sizeof(int);
  2503.                          i++)
  2504.                          printf("\n%d",intsSorted[i]);
  2505.                     free(intsSorted);
  2506.                }
  2507.                FLclear(&l);
  2508.                return 0;
  2509.           }
  2510.  
  2511.  
  2512.           The FLcomparE macro, defined in flexlist.h, is used to
  2513.           precisely type cast intcmp to the type required by
  2514.           FLsort.
  2515. FLpackPtrs              Compaction
  2516.  
  2517.  
  2518. *    Summary
  2519.  
  2520.           #include <flexlist.h>
  2521.  
  2522.           void ** FLpackPtrs(FlexL L);
  2523.  
  2524. *    Description
  2525.  
  2526.           FLpackPtrs allocates enough memory to hold a NULL
  2527.           terminated array of pointers that point to the data
  2528.           areas of all the FlexNodes in the FlexList.
  2529.  
  2530. *    Return Value
  2531.  
  2532.           If memory is exhausted, FLpackPtrs returns NULL,
  2533.           otherwise it returns a pointer to an array of void
  2534.           pointers.  You must type cast the void pointers to
  2535.           pointers to the type of data you are storing in the
  2536.           FlexList.  The array is zero terminated to facilitate
  2537.           processing.  You must explicitly free the array when it
  2538.           is no longer needed.
  2539.  
  2540. *    See Also
  2541.  
  2542.           FLpack, FLunpack, FLunpackNew
  2543.  
  2544. *    Example
  2545.  
  2546.           #include <stdio.h>       /*  printf()  */
  2547.           #include <stdlib.h>      /*  free()  */
  2548.           #include <flexlist.h>
  2549.  
  2550.           main()
  2551.           {
  2552.                FlexList l;  char **c; int i;
  2553.  
  2554.                FLstr(&l);   FLinsQD(&l,"one");
  2555.                FLinsQD(&l,"two");  FLinsQD(&l,"three");
  2556.                if ((c = (char **)FLpackPtrs(&l))
  2557.                     != (char **) 0)  {
  2558.                     for (i = 0; c[i]; i++)
  2559.                          printf("\n%s",c[i]);
  2560.                     free(c);
  2561.                }
  2562.                FLclear(&l);
  2563.                return 0;
  2564.           }
  2565. FLpopD                  Stack & Queue Access
  2566.  
  2567.  
  2568. *    Summary
  2569.  
  2570.           #include <flexlist.h>
  2571.  
  2572.           int FLpopD(FlexL L, void *D);
  2573.  
  2574. *    Description
  2575.  
  2576.           FLpopD copies the data from the first node to the
  2577.           address specified.  If no address is given then no data
  2578.           is copied.  FLpopD deletes the first node whether or
  2579.           not a copy operation is performed.
  2580.  
  2581. *    Return Value
  2582.  
  2583.           FLpopD returns 1 if a node was popped, otherwise it
  2584.           returns 0.
  2585.  
  2586. *    See Also
  2587.  
  2588.           FLtopD, FLinsQD, FLpopN, FLpushD, FLdelD, FLinsD
  2589.  
  2590. *    Example
  2591.  
  2592.           #include <stdio.h>       /*  printf()  */
  2593.           #include <flexlist.h>
  2594.  
  2595.           char *txt[] = { "Now is the time", 
  2596.                "for all smarter working",
  2597.                "programmers to spring for", "FlexList!" };
  2598.  
  2599.           main()
  2600.           {
  2601.                FlexList q;
  2602.                char *c;
  2603.  
  2604.                FLunpack(&q,sizeof(txt[0]),sizeof(txt)/
  2605.                     sizeof(txt[0]),txt);
  2606.                while (FLpopD(&q,&c)) 
  2607.                     printf("\n%s",c);
  2608.                return 0;
  2609.           }
  2610.  
  2611.           The program initializes the FlexList with FlexNodes
  2612.           containing pointers to all the strings of the txt
  2613.           array.  Pointers to the strings are popped and the
  2614.           strings displayed.
  2615. FLpopN                  Stack & Queue Access
  2616.  
  2617.  
  2618. *    Summary
  2619.  
  2620.           #include <flexlist.h>
  2621.  
  2622.           FlexN  FLpopN(FlexL L);
  2623.  
  2624. *    Description
  2625.  
  2626.           FLpopN unlinks the first node of the list if there is
  2627.           one.
  2628.  
  2629. *    Return Value
  2630.  
  2631.           FLpopN returns a pointer to the now dangling node or
  2632.           NULL if there is no node to unlink.  The dangling node
  2633.           must be relinked into a compatible FlexList with a
  2634.           FlexList function ending with "N" or otherwise
  2635.           explicitly freed.  Two FlexLists are said to be
  2636.           compatible if the sizes of the data areas in the
  2637.           FlexNodes are equal.  With a variant lists the
  2638.           sizeofNodeData fields will both be zero.  Instead you
  2639.           should use FLisVariant to make sure the virtual
  2640.           function table pointers are equal.
  2641.  
  2642. *    See Also
  2643.  
  2644.           FLdelN, FLinsQN, FLpopD, FLisVariant
  2645.  
  2646. *    Example
  2647.  
  2648.           #include <stdio.h>       /*  printf()  */
  2649.           #include <string.h>      /*  strcmp()  */
  2650.           #include <flexlist.h>
  2651.  
  2652.           char *greetings[] = {  "hello",  "goodbye", 
  2653.                "hi", "bye", "hey there" };
  2654.  
  2655.           int StrCmp(char **s1, char **s2)
  2656.           {  return strcmp(*s1,*s2); }
  2657. FLpopN
  2658.  
  2659.  
  2660.           main()
  2661.           {
  2662.                FlexList srcq, dstl;
  2663.  
  2664.                FLunpack(&srcq,sizeof(greetings[0]),
  2665.                     sizeof(greetings)/sizeof(greetings[0]),
  2666.                     greetings);
  2667.                FLfixed(&dstl,FLsizeofNodeData(&srcq));
  2668.                FLsetCompare(&dstl,FLcomparE(StrCmp));
  2669.                while (FLnotFull(&dstl) && FLnodes(&srcq))
  2670.                     FLinsSortN(&dstl,FLpopN(&srcq));
  2671.                while (FLnodes(&dstl))  {
  2672.                     printf("\n%s",*(char **)FLfrontD(&dstl));
  2673.                     FLpopD(&dstl,(void *)0);
  2674.                }
  2675.                FLclear(&srcq); FLclear(&dstl);
  2676.                return 0;
  2677.           }
  2678.  
  2679.           This program first builds a FlexList of character
  2680.           pointers to greeting strings.  It then sorts the list
  2681.           by building a new list and performing an insertion
  2682.           sort.  Lastly, it displays the sorted strings.  Notice
  2683.           that the greetings array does not have any 0
  2684.           terminator.  That's okay because the FlexList
  2685.           constructor is told how many cells there are in the
  2686.           array.
  2687.  
  2688.           The FLcomparE macro, defined in flexlist.h, precisely
  2689.           type casts my compare function pointer to the type
  2690.           require by both FLsetComare and FLsort.
  2691.  
  2692.           Please note how I type casted the void pointer returned
  2693.           by FLfrontD in order to access "by reference" the data
  2694.           in the front FlexNode.
  2695.  
  2696.           FLpopD discards the data when popping the top node
  2697.           because I passed the NULL void pointer as an address.
  2698.  
  2699.            FLprevD       List Access
  2700.  
  2701.  
  2702. *    Summary
  2703.  
  2704.           #include <flexlist.h>
  2705.  
  2706.           void * FLprevD(FlexL L, void *D);
  2707.  
  2708. *    Description
  2709.  
  2710.           FLprevD makes the previous node the new current node
  2711.           and copies data from that node to the address specified
  2712.           above.  If the address is NULL, the copying operation
  2713.           doesn't take place but the previous node is still made
  2714.           current.  If there is no previous node then current
  2715.           becomes undefined and curNum is set to 0.
  2716.  
  2717. *    Return Value
  2718.  
  2719.           FLprevD returns a pointer to the data area of the
  2720.           previous node.  If there is no previous node, then NULL
  2721.           is returned.
  2722.  
  2723. *    See Also
  2724.  
  2725.           FLnextD, FLmkcur, FLrecallD, FLstoreD
  2726.  
  2727. *    Example
  2728.  
  2729.           #include <stdio.h>       /*  printf()  */
  2730.           #include <flexlist.h>
  2731.  
  2732.           char *txt[] = { "Now is the time", 
  2733.                "for all smarter working",
  2734.                "programmers to spring for",
  2735.                "FlexList!", 0 };
  2736.  
  2737.           main()  /*  display the strings of txt[]  */
  2738.           {
  2739.                FlexList l;
  2740.                char buf[80];
  2741.                int i;
  2742.  
  2743.                FLstr(&l);
  2744.                for (i = 0; txt[i]; i++)
  2745.                     FLpushD(&l,txt[i]);
  2746.                while (FLprevD(&l,buf))
  2747.                     printf("\n%s",buf);
  2748.                FLclear(&l);
  2749.                return 0;
  2750.           } FLpushD      Stack Access
  2751.  
  2752. *    Summary
  2753.  
  2754.           #include <flexlist.h>
  2755.  
  2756.           void * FLpushD(FlexL L, const void *D);
  2757.  
  2758. *    Description
  2759.  
  2760.           Push a new node onto the FlexList "stack."  If an
  2761.           address for data is specified, copy that data to the
  2762.           new node.  If D is NULL and the FlexList is variant,
  2763.           FLpushD can't allocate a new FlexNode since it doesn't
  2764.           know how big to make it.
  2765.  
  2766. *    Return Value
  2767.  
  2768.           FLpushD returns a pointer to the data area of the newly
  2769.           pushed node.  If dynamic memory is exhausted or FLpushD
  2770.           is otherwise unable to push a new node, NULL, i.e.
  2771.           (void *) 0, is returned.
  2772.  
  2773. *    See Also
  2774.  
  2775.           FLpopD, FLpushN, FLinsD, FLinsQD, FLinsSortD
  2776.  
  2777. *    Example
  2778.  
  2779.           #include <stdio.h>       /*  printf()  */
  2780.           #include <flexlist.h>
  2781.  
  2782.           char *txt[] = { "Now is the time", 
  2783.                "for all smarter working",
  2784.                "programmers to spring for", "FlexList!", 0 };
  2785.  
  2786.           main()         /*  stack char pointers  */
  2787.           {
  2788.                FlexList s;
  2789.                char *c;
  2790.                int i;
  2791.  
  2792.                FLfixed(&s,sizeof(txt[0]));
  2793.                for (i = 0; txt[i]; i++)
  2794.                     FLpushD(&s,&txt[i]);
  2795.                while (FLpopD(&s,&c))
  2796.                     printf("\n%s",c);  /* read lines backward */
  2797.           }
  2798.  
  2799. FLpushN                 Stack Access
  2800.  
  2801.  
  2802. *    Summary
  2803.  
  2804.           #include <flexlist.h>
  2805.  
  2806.           void * FLpushN(FlexL L, FlexN N);
  2807.  
  2808. *    Description
  2809.  
  2810.           FLpushN relinks the given FlexNode onto the front of
  2811.           the FlexList.
  2812.  
  2813. *    Return Value
  2814.  
  2815.           FLpushN returns a pointer to the data area of the node
  2816.           just pushed.  If FLpushN fails to push the node, it
  2817.           returns NULL, i.e. FlexN0 defined in flexlist.h.
  2818.  
  2819. *    See Also
  2820.  
  2821.           FLpopN, FLinsQN, FLinsN, FLdelN, FLinsSortN, FLpushD
  2822.  
  2823. *    Example
  2824.  
  2825.           #include <stdio.h>       /*  printf()  */
  2826.           #include <flexlist.h>
  2827.  
  2828.           char *txt[] = { "Now is the time", 
  2829.                "for all smarter working",
  2830.                "programmers to spring for", "FlexList!" };
  2831.  
  2832.           main()
  2833.           {
  2834.                FlexList l, s;
  2835.                char *c;
  2836.  
  2837.                FLunpack(&l,sizeof(txt[0]),sizeof(txt)/
  2838.                     sizeof(txt[0]),txt);
  2839.                FLfixed(&s,FLsizeofNodeData(&l));
  2840.                while (FLnotFull(&s) && FLnodes(&l))
  2841.                     FLpushN(&s,FLpopN(&l));
  2842.                while (FLpopD(&s,&c)) 
  2843.                     printf("\n%s",c);  /* read lines backward */
  2844.                return 0;
  2845.           }
  2846.  
  2847.       FLrearD            Header & Queue Access
  2848.  
  2849.  
  2850. *    Summary
  2851.  
  2852.           #include <flexlist.h>
  2853.  
  2854.           void * FLrearD(FlexL L);
  2855.  
  2856. *    Return Value
  2857.  
  2858.           The FLrearD macro returns a pointer to the data area of
  2859.           the rear node.  If there are no nodes in the list it
  2860.           returns NULL, i.e. (void *) 0.
  2861.  
  2862. *    See Also
  2863.  
  2864.           FLfrontD, FLcurrentD, FLnextD, FLprevD
  2865.  
  2866. *    Example
  2867.  
  2868.           #include <stdio.h>       /*  printf()  */
  2869.           #include <flexlist.h>
  2870.  
  2871.           char *txt[] = { "FlexList!", 
  2872.                "programmers to spring for",
  2873.                "for all smarter working",
  2874.                "Now is the time" };
  2875.  
  2876.           main()
  2877.           {
  2878.                FlexList q;
  2879.                char **c;
  2880.  
  2881.                FLunpack(&q,(sizeof(txt[0]),sizeof(txt)/
  2882.                     sizeof(txt[0]),txt);
  2883.                FLmkcur(&q,FLnodes(&q));
  2884.                while ((c = FLrearD(&q)) != (char **)0)  {
  2885.                     printf("n%s",*c);
  2886.                     FLdelD(&q,(void *)0);
  2887.                }
  2888.           }
  2889.  
  2890.           The last node is made current to enable FLdelD to walk
  2891.           across the list backwards.  A pointer to the data in
  2892.           the rear node is used to display the string.
  2893. FLrecallD               Array Access
  2894.  
  2895.  
  2896. *    Summary
  2897.  
  2898.           #include <flexlist.h>
  2899.  
  2900.           int FLrecallD(FlexL L, void *D, unsigned n);
  2901.  
  2902. *    Description
  2903.  
  2904.           FLrecallD copies the data from the requested node, n,
  2905.           to the address specified by D.  If the address is NULL
  2906.           the operation is aborted.  If the requested node is
  2907.           zero the current node is recalled.  If the requested
  2908.           node is out of range the operation is again aborted.
  2909.  
  2910.           FLmkcur is called internally by FLrecallD to make the
  2911.           requested node current.  FLmkcur determines which
  2912.           pointer (front, current, or rear) is closest to the
  2913.           requested node.  It then follows the FlexList's linkage
  2914.           from that closest pointer to the newly requested node. 
  2915.           The current pointer is left positioned at the new node.
  2916.  
  2917. *    Return Value
  2918.  
  2919.           FLrecallD returns 1 if successful, 0 otherwise.
  2920.      
  2921. *    See Also
  2922.  
  2923.           FLstoreD, FLmkcur
  2924.  
  2925. *    Example
  2926.  
  2927.           #include <stdio.h>       /*  printf()  */
  2928.           #include <flexlist.h>
  2929.  
  2930.           char *txt[] = { "Now is the time", 
  2931.                "for all smarter working",
  2932.                "programmers to spring for", 
  2933.                "FlexList!", (char *) 0 };
  2934. FLrecallD
  2935.  
  2936.  
  2937.           main() 
  2938.           {
  2939.                FlexList l;
  2940.                char buf[80];
  2941.                int i;
  2942.  
  2943.                FLstr(&l);
  2944.                for (i = 0; txt[i]; i++)
  2945.                     FLinsQD(&l,txt[i]);
  2946.                for (i = 1; FLrecallD(&l,buf,i); i++)
  2947.                     printf("\n%s",buf);
  2948.                FLclear(&l);
  2949.                return 0;
  2950.           }
  2951.  
  2952.  
  2953.           Program output:
  2954.  
  2955.                Now is the time
  2956.                for all smarter working
  2957.                programmers to spring for
  2958.                FlexList!
  2959.  
  2960. FLsetCompare            Header Access
  2961.  
  2962.  
  2963. *    Summary
  2964.  
  2965.           #include <flexlist.h>
  2966.  
  2967.           int FLsetCompare(
  2968.                FlexL L,
  2969.                int (*compare)
  2970.                     (const void *D1, const void *D2)
  2971.           );
  2972.  
  2973. *    Description
  2974.  
  2975.           FLsetCompare sets the FlexList's internal compare
  2976.           function pointer to point to a user defined compare
  2977.           function.  Your compare function returns -1, 0, or 1 to
  2978.           indicate whether the first data being compared is less
  2979.           than, equal to, or greater than the second,
  2980.           respectively.  The compare function is used by FLsort,
  2981.           FLinsSortN, and FLinsSortD.  The compare function is
  2982.           also used for matching in FLfindFirstD, FLfindNextD,
  2983.           FLfindLastD, and FLfindPrevD.
  2984.  
  2985. *    Return value
  2986.  
  2987.           FLsetCompare returns true if L is not NULL.
  2988.  
  2989. *    Remarks
  2990.  
  2991.           It is common to have several different compare
  2992.           functions to search or sort a FlexList on various keys,
  2993.           in various orders.
  2994.  
  2995.           If you want to inhibit FlexList's binary searches and
  2996.           sorts then call FLsetCompare with FLcompare0, the NULL
  2997.           compare function pointer constant defined in
  2998.           flexlist.h.
  2999.  
  3000. *    See also
  3001.  
  3002.           FLsort, FLcompare, FLisSorted, FLunSort, FLfindFirstD,
  3003.           FLfindNextD, FLfindLastD, FLfindPrevD
  3004. FLsetCompare
  3005.  
  3006.  
  3007. *    Example
  3008.  
  3009.           #include <stdio.h>       /*  printf()  */
  3010.           #include <flexlist.h>
  3011.  
  3012.           int a[] = { 101, 2, 6, 3, 2, 8, 9, 13, 56 };
  3013.  
  3014.           int intMatch(int *i1, int *i2)
  3015.           {  return !(*i1 == *i2); }
  3016.  
  3017.           main()
  3018.           {
  3019.                FlexList l;
  3020.                int i = 2;
  3021.  
  3022.                FLunpack(&l,sizeof(a[0]),sizeof(a)/
  3023.                     sizeof(a[0]),a);
  3024.                FLsetCompare(&l,FLcomparE(intMatch));
  3025.                if (FLfindFirstD(&l,&i))
  3026.                     printf("\nFound %d in node %d : %d",
  3027.                          i,FLcurNum(&l),*(int *)FLcurrentD(&l));
  3028.                FLclear(&l);
  3029.                return 0;
  3030.           }
  3031.  
  3032.           Please note that the compare function only matches and
  3033.           doesn't reveal an ordering.  Don't call FLinsSortD or
  3034.           another function requiring the compare function to act
  3035.           as the test in a binary search - it will only be very
  3036.           confused since greater than and less than conditions
  3037.           can't be determined!
  3038.  
  3039.           The FLcomparE macro is used to precisely type cast my
  3040.           match function to the compare type required by FLsort
  3041.           and FLsetCompare.  It is defined in flexlist.h.
  3042.  
  3043. FLsetMaxNodes           Header Access
  3044.  
  3045.  
  3046. *    Summary
  3047.  
  3048.           #include <flexlist.h>
  3049.  
  3050.           int FLsetMaxNodes(FlexL L, unsigned maxNodes);
  3051.  
  3052. *    Description
  3053.  
  3054.           FLsetMaxNodes set the upper limit on FlexNodes that a
  3055.           FlexList is allowed to contain.  FLmaxMaxNodes is
  3056.           defined in flexlist.h as the maximum number allowed in
  3057.           any FlexList.
  3058.  
  3059. *    Return value
  3060.  
  3061.           FLsetMaxNodes returns true if it is successful in
  3062.           establishing the new limit.  The new limit must be
  3063.           greater than or equal to the number of nodes already in
  3064.           the FlexList.
  3065.  
  3066. *    See also
  3067.  
  3068.           FLmaxNodes, FLnodes, FLnotFull
  3069.  
  3070. *    Example
  3071.  
  3072.           #include <stdio.h>       /*  printf()  */
  3073.           #include <flexlist.h>
  3074.  
  3075.           main()
  3076.           {    
  3077.                FlexList q;
  3078.                int i = 1;
  3079.  
  3080.                FLfixed(&q,sizeof(int));
  3081.                printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
  3082.                printf("\n  - Vacancies: %u",FLnotFull(&q));
  3083.                printf("\n  = FlexNodes: %u",FLnodes(&q));
  3084.                FLsetMaxNodes(&q,35);
  3085.                FLinsQD(&q,&i);
  3086.                printf("\nMax FlexNodes: %u",FLmaxNodes(&q));
  3087.                printf("\n  - Vacancies: %u",FLnotFull(&q));
  3088.                printf("\n  = FlexNodes: %u",FLnodes(&q));
  3089.                FLclear(&q);
  3090.                return 0;
  3091.           }
  3092. FLsizeofNodeData        Header Access
  3093.  
  3094.  
  3095. *    Summary
  3096.  
  3097.           #include <flexlist.h>
  3098.  
  3099.           unsigned FLsizeofNodeData(FlexL L);
  3100.  
  3101. *    Return Value
  3102.  
  3103.           The FLsizeofNodeData macro returns the sizeofNodeData
  3104.           field in the FlexList's header.  The sizeofNodeData
  3105.           field tells FlexList functions how big the data is that
  3106.           is warehoused in the FlexList.  FlexLists are said to
  3107.           be compatible if their data sizes are equal.  Only
  3108.           FlexLists that are compatible can have their nodes
  3109.           swapped.  
  3110.  
  3111. *    Remarks
  3112.  
  3113.           Variant FlexLists have their sizeofNodeData fields set
  3114.           to zero.  This is because the data size is unknown -
  3115.           the virtual functions determine that.  If two FlexLists
  3116.           use the same virtual function table, their data are
  3117.           most likely compatible.  You'll have to make that
  3118.           determination.  Use FLisVariant to retrieve a pointer
  3119.           to a FlexList's virtual function table.
  3120.  
  3121. *    See Also
  3122.  
  3123.           FLfixed, FLvariant
  3124.  
  3125. *    Example
  3126.  
  3127.           #include <flexlist.h>
  3128.           int a[] = { 1, 2, 3, 4, 5 };
  3129.  
  3130.           main()
  3131.           {
  3132.                FlexList s, q;
  3133.  
  3134.                FLunpack(&s,sizeof(a[0]),sizeof(a)/
  3135.                     sizeof(a[0]),a);
  3136.                FLfixed(&q,FLsizeofNodeData(&s));
  3137.                while (FLnotFull(&q) && FLnodes(&s))
  3138.                     FLpushN(&q,FLpopN(&s));
  3139.                ...
  3140.                FLclear(&s);
  3141.                FLclear(&q);
  3142.           }
  3143. FLsort                  Sort
  3144.  
  3145.  
  3146. *    Summary
  3147.  
  3148.      #include <flexlist.h>
  3149.  
  3150.      int FLsort(
  3151.                FlexL L, 
  3152.                int (*compare)(
  3153.                     const void *D1, 
  3154.                     const void *D2
  3155.                )
  3156.      );
  3157.  
  3158. *    Description
  3159.  
  3160.           Sorts the FlexList in the order specified by compare. 
  3161.           The compare function specifies the order to sort by
  3162.           returning -1, 0, or 1 indicating that the data in the
  3163.           node under test is less than, equal to, or greater than
  3164.           the data in the node being moved respectively.  Note
  3165.           that different compare functions will result in
  3166.           different sorted orders since the compare function can
  3167.           be written to test different fields of the data.  The
  3168.           addresses passed to the compare functions point to the
  3169.           whole data areas.  The compare function must apply the
  3170.           test to the appropriate fields in these data areas. 
  3171.           These data areas are assumed to be the same type as
  3172.           that which the FlexList was constructed for.  The
  3173.           binary search algorithm is employed.
  3174.  
  3175.           FLsort resets the current node as undefined.
  3176.  
  3177. *    See Also
  3178.           
  3179.           FLfind...D, FLinsSortD, FLinsSortN
  3180.  
  3181. *    Example
  3182.  
  3183.           #include <stdio.h>       /*  printf()  */
  3184.           #include <string.h>      /*  strcmp()  */
  3185.           #include <flexlist.h>
  3186.  
  3187.           char *greetings[] = {  "hello",  "goodbye", 
  3188.                "hi", "bye", "hey there", (char *) 0 };
  3189. FLsort
  3190.  
  3191.  
  3192.           main()
  3193.           {
  3194.                FlexList l;
  3195.                char buf[80];
  3196.                int i;
  3197.  
  3198.                FLstr(&l);
  3199.                for (i = 0; greetings[i]; i++)
  3200.                     FLinsQD(&l,greetings[i]);
  3201.                printf("\nUnsorted:");
  3202.                while (FLnextD(&l,buf))
  3203.                     printf("\n%s",buf);
  3204.                FLsort(&l,FLcomparE(strcmp));
  3205.                printf("\n\nSorted:");
  3206.                while (FLnextD(&l,buf))
  3207.                     printf("\n%s",buf);
  3208.                FLclear(&l);
  3209.                return 0;
  3210.           }
  3211.  
  3212.  
  3213.           This program first builds a FlexList of greeting
  3214.           strings.  It then sorts the list.
  3215.  
  3216.           The FLcomparE macro, defined in flexlist.h, precisely
  3217.           type casts my compare function pointer to the type
  3218.           required by FLsort.
  3219.  
  3220. FLstoreD                Array Access
  3221.  
  3222.  
  3223. *    Summary
  3224.  
  3225.           #include <flexlist.h>
  3226.  
  3227.           int FLstoreD(FlexL L, const void *D, unsigned n);
  3228.  
  3229. *    Description
  3230.  
  3231.           FLstoreD writes the data specified into the node
  3232.           specified.  If n is 0, then the current node is assumed
  3233.           to be the node to store in.  If the data's address is
  3234.           NULL the operation is aborted or if the requested node
  3235.           is out of range of the FlexList.
  3236.  
  3237.           FLmkcur is called internally by FLstoreD to make the
  3238.           requested node current.  FLmkcur determines which
  3239.           pointer (front, current, or rear) is closest to the
  3240.           requested node.  It then follows the FlexList's linkage
  3241.           from that closest pointer to the newly requested node. 
  3242.           The current pointer is left positioned at the new node.
  3243.  
  3244. *    Return Value
  3245.  
  3246.           If successful FLstoreD returns 1, otherwise 0.
  3247.  
  3248. *    Remarks
  3249.  
  3250.           With variant FlexLists, e.g. those created with FLstr,
  3251.           etc., the writing of data is limited to the length of
  3252.           the data already present in the node.  This makes sense
  3253.           since the FlexNode is just big enough to accommodate
  3254.           the former data.
  3255.  
  3256. *    See Also
  3257.  
  3258.           FLrecallD, FLmkcur, FLstr, FLvariant
  3259.  
  3260. *    Example
  3261.  
  3262.           #include <stdio.h>       /*  printf()  */
  3263.           #include <flexlist.h>
  3264.  
  3265.           char *txt[] = { "Now is the time", 
  3266.                "for all smarter working",
  3267.                "programmers to spring for", 
  3268.                "FlexList!", (char *) 0 };
  3269. FLstoreD
  3270.  
  3271.  
  3272.           main() 
  3273.           {
  3274.                FlexList l;
  3275.                char buf[80];
  3276.                int i;
  3277.  
  3278.                FLstr(&l);
  3279.                for (i = 0; txt[i]; i++)
  3280.                     FLinsQD(&l,txt[i]);
  3281.                FLstoreD(&l,"for all overworked     and tired",2);
  3282.                FLmkcur(&l,0);
  3283.                while (FLnextD(&l,buf))
  3284.                     printf("\n%s",buf);
  3285.                FLclear(&l);
  3286.                return 0;
  3287.           }
  3288.  
  3289.  
  3290.           Program output:
  3291.  
  3292.                Now is the time
  3293.                for all overworked
  3294.                programmers to spring for
  3295.                FlexList!
  3296. FLstr                   Static Constructor
  3297.  
  3298.  
  3299. *    Summary
  3300.  
  3301.           #include <flexlist.h>
  3302.  
  3303.           FlexL FLstr(FlexL L);
  3304.  
  3305. *    Description
  3306.  
  3307.           The FLstr macro expands into a call to FLvariant with a
  3308.           virtual function table for processing C strings.  The
  3309.           FlexList is initialized to contain only FlexNodes big
  3310.           enough for the C strings held within.  All FlexLists
  3311.           functions are available; however, FLstoreD will limit
  3312.           the string being stored to the length of the string it
  3313.           is overwriting.  This prevents FLstoreD from writing
  3314.           pass the end of the FlexNode.
  3315.  
  3316. *    Return value
  3317.  
  3318.           FLstr returns L if successful otherwise it returns
  3319.           FlexL0, the NULL FlexList pointer defined in
  3320.           flexlist.h.
  3321.  
  3322. *    Remarks
  3323.  
  3324.           When copying data from variant string FlexLists, you
  3325.           must insure that the receiving string buffer is big
  3326.           enough to accommodate the largest string that may be
  3327.           encountered.
  3328.  
  3329.           Be sure to read on the section on FLvariant for an
  3330.           explanation of how FLstr works.
  3331.  
  3332. *    See also
  3333.  
  3334.           FLstrNew, FLvariant
  3335. FLstr
  3336.  
  3337.  
  3338. *    Example
  3339.  
  3340.           #include <stdio.h>       /*  printf()  */
  3341.           #include <flexlist.h>
  3342.  
  3343.           main()
  3344.           {
  3345.                FlexList l;
  3346.                char s[80];
  3347.  
  3348.                FLstr(&l);
  3349.                FLinsQD(&l,"one dog");
  3350.                FLinsQD(&l,"two cats");
  3351.                FLinsQD(&l,"three crows");
  3352.                while (FLnextD(&l,s))
  3353.                     printf("\n%s",s);
  3354.                FLstoreD(&l,"three cat birds",FLnodes(&l)); 
  3355.                     /* truncates to length of "three crows"!  */
  3356.                FLsort(&l,FLcomparE(strcmp));
  3357.                FLmkcur(&l,0);
  3358.                while (FLnextD(&l,s))  
  3359.                     printf("\n%s",s);
  3360.                FLclear(&l);
  3361.                return 0;
  3362.           }
  3363.  
  3364.           The FLcomparE macro, defined in flexlist.h, precisely
  3365.           type casts to the function pointer type required by the
  3366.           FLsort and FLsetCompare functions.
  3367. FLstrNew                Dynamic Constructor
  3368.  
  3369.  
  3370. *    Summary
  3371.  
  3372.           #include <flexlist.h>
  3373.  
  3374.           FlexL FLstrNew(size_t sizeofLocalData,
  3375.                int (*FLDdestruct)(void *LD));
  3376.  
  3377. *    Description
  3378.  
  3379.           The FLstrNew macro expands to a call to FLvariantNew
  3380.           which dynamically allocates and initializes a FlexList
  3381.           with room enough in the header to store user data of
  3382.           the size sizeofLocalData and the FlexNodes just big
  3383.           enough to hold C strings.  FLDdestruct is the user
  3384.           defined function that must be successfully called by
  3385.           FLdelete before a FlexList will be cleared and
  3386.           deallocated.  FLDdestruct is called with the address of
  3387.           the user data in the FlexList header.  It must return a
  3388.           non zero value if the FlexList is every to be disposed
  3389.           of.
  3390.  
  3391. *    Return value
  3392.  
  3393.           FLstrNew returns a pointer to the newly allocated
  3394.           FlexList or FlexL0 if it fails.  FlexL0 is the NULL
  3395.           FlexList pointer constant defined in flexlist.h
  3396.  
  3397. *    Remarks
  3398.  
  3399.           Be sure to read the entries for FLstr and FLvariant and
  3400.           FLvariantNew to better understand the operation of
  3401.           variant FlexLists.
  3402.  
  3403. *    See also
  3404.  
  3405.           FLstr, FLvariant, FLvariantNew, FLdelete
  3406.  
  3407. *    Example
  3408.  
  3409.           See examples for FLvariant, FLvariantNew, FLfixedNew
  3410. FLtopD                  Stack & Queue Access
  3411.  
  3412.  
  3413. *    Summary
  3414.  
  3415.           #include <flexlist.h>
  3416.  
  3417.           void * FLtopD(FlexL L, void *D);
  3418.  
  3419. *    Description
  3420.  
  3421.           FLtopD fetches a copy of the data in the first node of
  3422.           the list if an address is specified for D.
  3423.      
  3424. *    Return Value
  3425.  
  3426.           If there are no nodes then FLtopD returns NULL
  3427.           otherwise FLtopD returns a pointer to the data area of
  3428.           the top node.
  3429.  
  3430. *    See Also
  3431.  
  3432.           FLfrontD, FLpopD
  3433.  
  3434. *    Example
  3435.  
  3436.           #include <stdio.h>       /*  printf()  */
  3437.           #include <flexlist.h>
  3438.  
  3439.           int ints[] = { 1, 2, 3, 4 };
  3440.  
  3441.           main()
  3442.           {
  3443.                FlexList s;
  3444.                int i;
  3445.  
  3446.                FLunpack(&s,sizeof(ints[0]),sizeof(ints)/
  3447.                     sizeof(ints[0]),ints);
  3448.                while (FLtopD(&s,&i))  {
  3449.                     printf("\n%d",i);
  3450.                     FLpopD(&s,(void *)0);
  3451.                }
  3452.           }
  3453.  
  3454.           The program initializes the FlexList to hold four
  3455.           integers.  The integers are displayed and popped.
  3456. FLunpack                Static Constructor
  3457.  
  3458.  
  3459. *    Summary
  3460.  
  3461.           #include <flexlist.h>
  3462.  
  3463.           FlexL  FLunpack(FlexL L, size_t sizeofCell,
  3464.                unsigned cells, const void *array);
  3465.  
  3466. *    Description
  3467.  
  3468.           This FlexList constructor initializes the FlexList
  3469.           pointed to by L with enough FlexNodes of the proper
  3470.           size to hold all the cells of the specified array. 
  3471.           Each node contains a copy of one cell of the given
  3472.           array.  You can think of this constructor as exploding
  3473.           a conventional C array into a FlexList.  MaxNodes is
  3474.           set to FLmaxMaxNodes, the maximum allowed for any
  3475.           FlexList which is UINT_MAX (the largest value of an
  3476.           unsigned integer).
  3477.  
  3478. *    Return value
  3479.  
  3480.           If successful, FLunpack returns L otherwise it returns
  3481.           FlexL0 which is defined in flexlist.h as (FlexL) 0.
  3482.  
  3483. *    See Also
  3484.  
  3485.           FLunpackNew, FLpack, FLpackPtrs, FLfixed
  3486.  
  3487. *    Example
  3488.  
  3489.           #include <flexlist.h>
  3490.  
  3491.           float f[] = { 1.5, 2.1, 3.7, 4.4, 5.1 };
  3492.  
  3493.           main()  /*  add zero to front of array  */
  3494.           {
  3495.                FlexList l;
  3496.                float F = 0.0;
  3497.  
  3498.                (void) FLunpack( &l, sizeof(f[0]), sizeof(f) /
  3499.                     sizeof(f[0]), f);
  3500.                (void) FLpushD(&l,&F);
  3501.                ...
  3502.           }
  3503. FLunpackNew             Dynamic Constructor
  3504.  
  3505.  
  3506. *    Summary
  3507.  
  3508.           #include <flexlist.h>
  3509.  
  3510.           FlexL  FLunpackNew(
  3511.                size_t sizeofCell,
  3512.                unsigned cells,
  3513.                const void *array,
  3514.                size_t sizeofLocalData,
  3515.                int (*FLDdestruct)(void *LD)
  3516.           );
  3517.  
  3518. *    Description
  3519.  
  3520.           This FlexList constructor allocates and initializes a
  3521.           FlexList with enough FlexNodes of the proper size to
  3522.           hold all the cells of the specified array.  Each node
  3523.           contains a copy of one cell of the given array.  You
  3524.           can think of this constructor as exploding a
  3525.           conventional C array into a FlexList.  MaxNodes is set
  3526.           to FLmaxMaxNodes, the maximum allowed for any FlexList
  3527.           which is UINT_MAX (the largest value of an unsigned
  3528.           integer).
  3529.  
  3530.           The FlexList header is allocated large enough to hold
  3531.           user data of the size specified by sizeofLocalData.
  3532.  
  3533.           Use FLdelete to destruct dynamically allocated
  3534.           FlexLists.  FLdelete calls the user defined function
  3535.           FLDdestruct which is passed the address of user data in
  3536.           the FlexList header (the address is never NULL).  If
  3537.           your FLDdestruct function returns something other than
  3538.           zero, FLdelete will then call FLclear to destruct the
  3539.           FlexNodes and if that is successful, FLdelete then
  3540.           frees the dynamically allocated FlexList.  If your
  3541.           FLDdestruct function returns zero then FLdelete will
  3542.           return zero.
  3543.  
  3544. *    Return value
  3545.  
  3546.           If successful, FLunpackNew returns a pointer to a
  3547.           dynamically allocated FlexList, otherwise it returns
  3548.           FlexL0 which is defined in flexlist.h as (FlexL) 0.
  3549. FLunpackNew
  3550.  
  3551.  
  3552. *    Remarks
  3553.  
  3554.           If your dynamic FlexList doesn't need to store data in
  3555.           the FlexList header then pass zero to the
  3556.           sizeofLocalData parameter.
  3557.  
  3558.           If your application doesn't require a FLDdestruct
  3559.           function call FLunpackNew with the NULL pointer
  3560.           constant, FLDdestruct0, defined in flexlist.h.
  3561.  
  3562.           If your dynamic FlexList doesn't store data in the
  3563.           FlexList header, don't access data with FLData! 
  3564.           Likewise if you do specify a FLDdestruct function, be
  3565.           sure your function ignores the local data parameter
  3566.           passed to it!  A Flexlist doesn't maintain a
  3567.           sizeofLocalData field from which it can ascertain
  3568.           whether or not you store any data in the FlexList
  3569.           header.  This was a design consideration to save space
  3570.           in the header.
  3571.  
  3572.           Use FLData and FLisFixed to determine if a FlexList was
  3573.           constructed with FLfixedNew or FLunpackNew.  FLData
  3574.           returns true for dynamically allocated FlexLists.
  3575.  
  3576. *    See Also
  3577.  
  3578.           FLData, FLdelete, FLisFixed, FLunpack, FLpack,
  3579.           FLpackPtrs, FLfixed
  3580.  
  3581. *    Example
  3582.  
  3583.           This program builds a list of floats and then aliases
  3584.           it.  When FLdelete is called it won't destruct the
  3585.           FlexList until all references to it are destructed. 
  3586.           The link count is maintained in the header of the
  3587.           dynamically allocated FlexList.
  3588.  
  3589.  
  3590.           #include <stdio.h>       /*  printf()  */
  3591.           #include <flexlist.h>
  3592. FLunpackNew
  3593.  
  3594.  
  3595.           FlexL FLlinkInit(FlexL L)
  3596.           {
  3597.                int *links;
  3598.  
  3599.                if ((links = FLData(L)) != (int *) 0)
  3600.                     *links = 1;
  3601.                return L;
  3602.           }
  3603.  
  3604.           FlexL FLlink(FlexL L)
  3605.           {
  3606.                int *links;
  3607.  
  3608.                if ((links = FLData(L)) != (int *) 0)
  3609.                     ++*links;
  3610.                return L;
  3611.           }
  3612.  
  3613.           int FLunlinked(void *LD)
  3614.           {  /*  LD is never NULL!  */
  3615.                int *links = (int *) LD;
  3616.  
  3617.                if (--*links)
  3618.                     return 0;
  3619.                return 1;
  3620.           }
  3621. FLunpackNew
  3622.  
  3623.  
  3624.           float f[] = { 3.5, 7.9, 10.1 }
  3625.  
  3626.           main()
  3627.           {
  3628.                FlexL L1, L2;
  3629.  
  3630.                if ((L1 = FLlinkInit(FLunpackNew(sizeof(f[0]),
  3631.                     sizeof(f)/sizeof(f[0]),f,
  3632.                     sizeof(int),FLunlinked))) == FlexL0)
  3633.                     return 1;
  3634.                L2 = FLlink(L1);
  3635.                while (FLnextD(L1,&f))
  3636.                     printf("\n%f",f);
  3637.                FLdelete(&L1);  /*  FLdelete fails!  */
  3638.                printf("\n nodes in L1: %u",FLnodes(L1));
  3639.                /*  three nodes in L2 */
  3640.                printf("\n nodes in L2: %u",FLnodes(L2));
  3641.                while (FLnextD(L2,&f))
  3642.                     printf("\n%f",f);
  3643.                FLdelete(&L2);  /*  FLdelete succeeds!  */
  3644.                /*  FlexList is gone!  */
  3645.                L1 = FlexL0; 
  3646.                printf("\n nodes in L1: %u",FLnodes(L1));
  3647.                printf("\n nodes in L2: %u",FLnodes(L2));
  3648.                return 0;
  3649.           }
  3650.  
  3651.           The important thing to remember is that FLdelete calls
  3652.           your FLDdestruct which must return true before FLdelete
  3653.           will destruct the FlexList. 
  3654. FLunSort                Header Access
  3655.  
  3656.  
  3657. *    Summary
  3658.  
  3659.           #include <flexlist.h>
  3660.  
  3661.           int FLunSort(FlexL L);
  3662.  
  3663. *    Return value
  3664.  
  3665.           The FLunSort macro returns true if L is not NULL.  The
  3666.           sorted field in the FlexList header is reset to zero.
  3667.  
  3668. *    Remarks
  3669.  
  3670.           FLunSort is used primarily after a sort and subsequent
  3671.           key data modification via a pointer returned by
  3672.           FLnextD, FLprevD, or FLmkcur.  Any other modifications
  3673.           to the FlexList's sorted order can be determined
  3674.           automatically.
  3675.  
  3676. *    See Also
  3677.  
  3678.           FLsort, FLisSorted
  3679.  
  3680. *    Example
  3681.  
  3682.           #include <flexlist.h>
  3683.  
  3684.           int a[] = { 1, 2, 3, 4, 5 };
  3685.  
  3686.           int intCompare(int *i1, int *i2)
  3687.           { return ((*i1 < *i2)? -1 : (*i1 > *i2)? 1 : 0); }
  3688.  
  3689.           main()
  3690.           {
  3691.                FlexList l;
  3692.  
  3693.                FLunpack(&l,sizeof(a[0]),sizeof(a)/
  3694.                     sizeof(a[0]),a);
  3695.                /*  FLisSorted(&l) is false  */
  3696.                FLsort(&l,FLcomparE(intCompare));
  3697.                /*  FLisSorted(&l) is true  */
  3698.                *(int *)FLmkcur(&l,1) = 6;
  3699.                /*  FLisSorted(&l) is true */
  3700.                FLunSort(&l);
  3701.                /*  FLisSorted(&l) is false  */
  3702.                FLclear(&l);
  3703.           }         
  3704. FLvariant               Static Constructor
  3705.  
  3706.  
  3707. *    Summary
  3708.  
  3709.           #include  <flexlist.h>
  3710.  
  3711.           FlexL FLvariant(FlexL L, FlexNVFT vft);
  3712.  
  3713. *    Description
  3714.  
  3715.           FLvariant initializes the FlexList pointed to by L to
  3716.           hold variant length data.  Vft is a pointer to the
  3717.           virtual function table containing the pointers to user
  3718.           defined functions.  These functions tell the FlexList
  3719.           functions 1) how to create a new FlexNode from user
  3720.           data, 2) how to write user data to a FlexNode, 3) how
  3721.           to read user data from a FlexNode, and 4) how to
  3722.           dispose of user data when deleting a FlexNode.  These
  3723.           virtual functions allow a FlexList to handle most types
  3724.           of heterogeneous data.
  3725.  
  3726.           The sizeofNodeData field within the FlexList header is
  3727.           always zero for variant FlexLists.
  3728.  
  3729. *    Return value
  3730.  
  3731.           If successful, FLvariant returns L otherwise it returns
  3732.           FlexL0 which is defined in flexlist.h as (FlexL) 0.
  3733.  
  3734. *    Remarks
  3735.  
  3736.           You must define four functions:
  3737.  
  3738.                FlexN FNnew(const void *D);
  3739.                int   FNwrite(void *ND, const void *D);
  3740.                int   FNread(const void *ND, void *D);
  3741.                int   FNdestruct(void *ND, void *D);
  3742.  
  3743.           The above parameters are guaranteed never to be NULL
  3744.           except possibly the D in FNdestruct.  You can name your
  3745.           functions any way you like.  Return zero for all four
  3746.           functions if there is a failure, otherwise the FlexList
  3747.           function invoking them will assume that all is well and
  3748.           proceed.  If you want to inhibit a particular function
  3749.           just return zero for that function and any FlexList
  3750.           function requiring that function will return failure
  3751.           and in effect be inhibited for the life of your variant
  3752.           FlexList.
  3753. FLvariant
  3754.  
  3755.  
  3756.           You must then define and initialize a virtual function
  3757.           table:
  3758.  
  3759.                FlexNodeVFT YourVFT = { FNnew, FNwrite,
  3760.                     FNread, FNdestruct };
  3761.  
  3762.           Any of the virtual functions can be absent.  Use
  3763.           FNnew0, FNwrite0, FNread0, and/or FNdestruct0 as zero
  3764.           initializers.  The FlexList functions that call them
  3765.           will simply return a failure indication. 
  3766.  
  3767.           In this case the call to construct the FlexList would
  3768.           be:
  3769.  
  3770.                FlexList l;
  3771.  
  3772.                FLvariant(&l,&YourVFT);
  3773.  
  3774.           The FlexList functions that access user data by value
  3775.           will now work on your variant data the same way they
  3776.           did for fixed sized data.  You can think of these
  3777.           virtual functions as user definable hooks that FlexList
  3778.           "by value" functions call to allow the user's data to
  3779.           define its own size and how it's to be copied.
  3780.  
  3781.           Let's look at which FlexList functions use each virtual
  3782.           function.
  3783.  
  3784.                FNnew          FLpushD, FLinsQD, FLinsD, and
  3785.                               FLinsSortD
  3786.  
  3787.                FNwrite        FLstoreD
  3788.  
  3789.                FNread         FLtopD, FLnextD, FLprevD, FLrecallD
  3790.  
  3791.                FNdestruct     FLpopD, FLdelD, FLclear via FLpopD,
  3792.                               FLdelete via FLclear via FLpopD
  3793.  
  3794.           For example when FLpushD is called for a variant
  3795.           FlexList, FLpushD knows that it is a variant FlexList
  3796.           because the sizeofNodeData field in the FlexList's
  3797.           header is zero.  If the address of the data has been
  3798.           passed to FLpushD it then checks if the virtual
  3799.           function table is initialized with a function pointer
  3800.           for FNnew.  If so your FNnew is called with the address
  3801.           of the data passed to FLpushD.
  3802. FLvariant
  3803.  
  3804.  
  3805.           Your FNnew must determine how big the data is and
  3806.           allocate an appropriate FlexNode and copy the data to
  3807.           it.  If your FNnew is successful it returns a pointer
  3808.           to the newly allocated FlexNode initialized with a copy
  3809.           of your data.  Your FNnew indicates failure by
  3810.           returning FlexN0, the NULL FlexNode pointer constant
  3811.           defined in flexlist.h.
  3812.  
  3813.                FlexN YourFNnew(const void *D)
  3814.                {  /*  D is never NULL!  */
  3815.                     FlexN N;
  3816.  
  3817.                     if ((N = malloc( sizeof(FlexNode) +
  3818.                          sizeofYourData(D)-1)) != FlexN0)
  3819.                          memcpy(N->data,D,sizeofYourData(D));
  3820.                     return N;
  3821.                }
  3822.  
  3823.           Basically you need to allocate a FlexNode for the "size
  3824.           of your data" plus the sizeof(FlexNode) minus one. 
  3825.           It's up to you to figure out how to get your data
  3826.           copied into the FlexNode.  Just remember to start your
  3827.           copying at N->data!  You may even have suballocated
  3828.           dynamic memory to worry about.  Don't just copy
  3829.           embedded pointers to suballocated dynamic memory along
  3830.           with the data since two data structures would then
  3831.           "own" the memory pointed to.
  3832.  
  3833.           Writing to a FlexNode is very similar to creating a new
  3834.           initialized FlexNode except the FlexNode doesn't have
  3835.           to be allocated.  You need to be careful since you
  3836.           don't want to overwrite the end of the FlexNode with
  3837.           data that is longer than was originally in there!
  3838.  
  3839.                int YourFNwrite(void *ND, const void *D)
  3840.                {  /*  ND and D are never NULL!  */
  3841.                     if (sizeofYourData(ND) < sizeofYourData(D))
  3842.                          return 0;
  3843.                     memcpy(ND,D,sizeofYourData(D));
  3844.                     return 1;
  3845.                }
  3846.  
  3847.           Again you need to consider embedded pointers, etc.
  3848. FLvariant
  3849.  
  3850.  
  3851.           Let's look at a possible FNread function that simply
  3852.           copies the FlexNode data area "ND" to your data "D."
  3853.  
  3854.                int YourFNread(const void  *ND, void *D)
  3855.                {  /*  ND and D are never NULL!  */
  3856.                     memcpy(D,ND,sizeofYourData(ND));
  3857.                     return 1;
  3858.                }
  3859.  
  3860.           Again your data may be a complicated C structure with
  3861.           suballocated memory.  Whatever scheme you use to
  3862.           resolve double ownership of suballocated memory, make
  3863.           sure you keep it straight and don't leave dangling
  3864.           memory lying about by overwriting pointers in D!
  3865.  
  3866.           Let's take a look at a simple FNdestruct function.
  3867.  
  3868.                int YourFNdestruct(void *ND, void *D)
  3869.                {  /*  ND is never NULL;  D may be NULL!  */
  3870.                     if (D)
  3871.                          memcpy(D,ND,sizeofYourData(ND));
  3872.                     else  {
  3873.                          /*  free any suballocated memory  */
  3874.                     }
  3875.                     return 1;
  3876.                }
  3877.  
  3878.           Again you must be sure not to overwrite pointers in D
  3879.           without first deallocating any suballocated memory. 
  3880.           This time D might be NULL in which case you must be
  3881.           sure to deallocate any suballocated memory since the
  3882.           FlexNode will be discarded soon after your function
  3883.           returns.  I'm assuming that embedded pointers copied to
  3884.           D transfer suballocated memory to D.
  3885.  
  3886. *    See also
  3887.  
  3888.           FLvariantNew, FLstr, FLfixed
  3889.  
  3890. *    Example
  3891.  
  3892.           For our first example, let's see how FLstr constructs a
  3893.           variant FlexList for C strings.
  3894. FLvariant
  3895.  
  3896.  
  3897.           #include <stdio.h>       /*  printf()  */
  3898.           #include <string.h>      /*  strcmp()  */
  3899.           #include <flexlist.h>
  3900.  
  3901.           #ifdef definedInFlexlistC
  3902.           static FlexN FNnewStr(const void *D)
  3903.           {
  3904.                FlexN N;
  3905.                size_t i;
  3906.  
  3907.                for (i = 0; ((char *)D)[i++]; /* no reinit */)
  3908.                     /* null statement */;
  3909.                if ((N = malloc(sizeof(FlexNode)+i-1)) != FlexN0)
  3910.                     (void) memcpy(N->data,D,i);
  3911.                return N;
  3912.           }
  3913.  
  3914.           static int FNwriteStr(void *ND, const void *D)
  3915.           {
  3916.                char *nd, *d;
  3917.      
  3918.                nd = (char *) ND;
  3919.                d = (char *) D;
  3920.                while (*nd)
  3921.                     if ((*nd++ = *d++) == '\0')
  3922.                          break;
  3923.                return 1;
  3924.           }
  3925.  
  3926.           static int FNreadStr(const void *ND, void *D)
  3927.           {
  3928.                char *nd, *d;
  3929.      
  3930.                nd = (char *) ND;
  3931.                d = (char *) D;
  3932.                while ((*d++ = *nd++) != '\0')
  3933.                     /* null statement */;
  3934.                return 1;
  3935.           }
  3936. FLvariant
  3937.  
  3938.  
  3939.           static int FNdestructStr(void *ND, void *D)
  3940.           {
  3941.                char *nd, *d;
  3942.      
  3943.                nd = (char *)ND;
  3944.                if ((d = (char *)D) != (char *)0) 
  3945.                     while ((*d++ = *nd++) != '\0')
  3946.                          /* null statement */;
  3947.                return 1;
  3948.           }
  3949.  
  3950.           FlexNodeVFT FlexNodeStrVFT = { FNnewStr, FNwriteStr,
  3951.                FNreadStr, FNdestructStr };
  3952.           #endif
  3953.  
  3954.           #ifdef definedInFlexlistH
  3955.           #define FLstr(L) FLvariant(L,&FlexNodeStrVFT)
  3956.           #endif
  3957.  
  3958.           main()
  3959.           {
  3960.                FlexList l;
  3961.                char s[80];
  3962.  
  3963.                FLstr(&l);
  3964.                FLinsQD(&l,"one dog");   /* calls FNnew */
  3965.                FLinsQD(&l,"two cats");
  3966.                FLinsQD(&l,"three crows");
  3967.                while (FLnextD(&l,s))  /* calls FNread */
  3968.                     printf("\n%s",s);
  3969.                FLstoreD(&l,"three cat birds",FLnodes(&l)); 
  3970.                     /* calls FNwrite which truncates!  */
  3971.                FLsort(&l,FLcomparE(strcmp));
  3972.                FLmkcur(&l,0);
  3973.                while (FLnextD(&l,s))  
  3974.                     printf("\n%s",s);
  3975.                FLclear(&l); /* calls FNdestruct via FLpopD */
  3976.                return 0;
  3977.           }
  3978.  
  3979.           FLcomparE is defined in flexlist.h and does a precise
  3980.           type cast to the function pointer type required by the
  3981.           FLsort and FLsetCompare functions.
  3982. FLvariant
  3983.  
  3984.  
  3985.           In the second example, a FlexList is used to warehouse
  3986.           messages that have suballocated text strings.  A
  3987.           variant FlexList is used to control suballocated
  3988.           dynamic memory in what would otherwise be a fixed sized
  3989.           FlexNode FlexList.  The virtual functions are used to
  3990.           control the allocating and deallocating of the
  3991.           suballocated memory and thus prevent suballocated
  3992.           memory from being doubly owned or left dangling.
  3993.  
  3994.           The msgcpy function insures that the destination
  3995.           message's text string is freed before copying the
  3996.           source message.  The source message's text string is
  3997.           duplicated in the destination message.  FNdestructMsg
  3998.           frees the text string before returning to the calling
  3999.           FlexList function which will in turn free the FlexNode.
  4000.  
  4001.  
  4002.           #include <stdio.h>       /*  printf()  */
  4003.           #include <stdlib.h>      /*  malloc(), free()  */
  4004.           #include <string.h>      /*  strlen(), strcpy()  */
  4005.                                    /*  memcpy()  */
  4006.           #include <flexlist.h>
  4007.  
  4008.           typedef struct  {
  4009.                unsigned token;
  4010.                char *text;
  4011.           } msg, *msG;
  4012.  
  4013.           void msgput(msG M)
  4014.           {
  4015.                if (M)
  4016.                     printf("\n Token: %8u  text: %s",
  4017.                          M->token,M->text);
  4018.           }
  4019.  
  4020.           char *strdup(const char *s)
  4021.           {
  4022.                char *t;
  4023.  
  4024.                if (s)
  4025.                     if ((t = malloc((size_t)strlen(s)+1))
  4026.                          != (char *) 0)
  4027.                          return strcpy(t,s);
  4028.                return (char *) 0;
  4029.           }
  4030. FLvariant
  4031.  
  4032.  
  4033.           static void msgcpy(msG Mdst, msG Msrc)
  4034.           {  /*  Mdst and Msrc are never NULL!  */
  4035.                if (Mdst->text)
  4036.                     free(Mdst->text);
  4037.                (void) memcpy(Mdst,Msrc,sizeof(msg));
  4038.                Mdst->text = strdup(Msrc->text);
  4039.           }
  4040.  
  4041.           FlexN FNnewMsg(const void *D)
  4042.           {  /*  D is never NULL!  */
  4043.                FlexN N;
  4044.  
  4045.                if ((N = malloc(sizeof(msg)+sizeof(FlexNode)-1))
  4046.                     != FlexN0)  {
  4047.                     ((msG)(N->data))->text = (char *) 0;
  4048.                     msgcpy((msG)(N->data),(msG)D);
  4049.                }
  4050.                return N;
  4051.           }
  4052.  
  4053.           int FNwriteMsg(void *ND, const void *D)
  4054.           {  /*  ND and D are never NULL!  */
  4055.                msgcpy((msG)ND,(msG)D);
  4056.                return 1;
  4057.           }
  4058.  
  4059.           int FNreadMsg(const void *ND, void *D)
  4060.           {  /*  ND and D are never NULL!  */
  4061.                msgcpy((msG)D,(msG)ND);
  4062.                return 1;
  4063.           }
  4064.  
  4065.           int FNdestructMsg(void *ND, void *D)
  4066.           {  /*  ND is never NULL;  D may be NULL!  */
  4067.                if (D)
  4068.                     msgcpy((msG)D,(msG)ND);
  4069.                if (((msG)ND)->text)
  4070.                     free(((msG)ND)->text);
  4071.                return 1;
  4072.           }
  4073.  
  4074.           FlexNodeVFT FLmsgVFT = { FNnewMsg, FNwriteMsg,
  4075.                FNreadMsg, FNdestructMsg };
  4076. FLvariant
  4077.  
  4078.  
  4079.           main()
  4080.           {
  4081.                FlexList m;
  4082.                msg M;
  4083.  
  4084.                FLvariant(&m,&FLmsgVFT);
  4085.                M.token =  1; M.text = "one dog";
  4086.                FLinsQD(&m,&M);   /* calls FNnew */
  4087.                M.token =  2; M.text = "two cats";
  4088.                FLinsQD(&m,&M);
  4089.                M.token =  3; M.text = "three crows";
  4090.                FLinsQD(&m,&M);
  4091.  
  4092.                /* don't free string constant */
  4093.                M.text = (char *) 0;
  4094.  
  4095.                while (FLnextD(&m,&M))  /* calls FNread */
  4096.                     msgput(&M);
  4097.                M.token = 3; M.text = "three cat birds";
  4098.                FLstoreD(&m,&M,FLnodes(&m)); /* calls FNwrite */
  4099.                FLmkcur(&m,0);
  4100.  
  4101.                /* don't free string constant */
  4102.                M.text = (char *) 0;
  4103.  
  4104.                while (FLnextD(&m,&M))  
  4105.                     msgput(&M);
  4106.                FLclear(&m); /* calls FNdestruct via FLpopD */
  4107.                return 0;
  4108.           }
  4109. FLvariantNew            Dynamic Constructor
  4110.  
  4111.  
  4112. *    Summary
  4113.  
  4114.           #include  <flexlist.h>
  4115.  
  4116.           FlexL FLvariantNew(
  4117.                FlexNVFT vft,
  4118.                size_t sizeofLocalData,
  4119.                int (*FLDdestruct)(void *LD)
  4120.           );
  4121.  
  4122. *    Description
  4123.  
  4124.           FLvariantNew allocates and initializes a FlexList big
  4125.           enough to hold user data within the FlexList header. 
  4126.           The FlexList can subsequently be used to warehouse
  4127.           variant data in the FlexNodes of the type handled by
  4128.           the virtual function table.  Vft is a pointer to the
  4129.           virtual function table containing the pointers to user
  4130.           defined functions.  These functions tell the FlexList
  4131.           functions 1) how to create a new FlexNode from user
  4132.           data, 2) how to write user data to a FlexNode, 3) how
  4133.           to read user data from a FlexNode, and 4) how to
  4134.           dispose of user data when deleting a FlexNode.  These
  4135.           virtual functions allow a FlexList to handle most types
  4136.           of heterogeneous data.
  4137.  
  4138.           The FlexList header can warehouse data of the size
  4139.           sizeofLocalData.  Use FLdelete to destruct dynamically
  4140.           allocated FlexLists.  FLdelete calls the user defined
  4141.           function FLDdestruct which is passed the address of
  4142.           user data in the FlexList header (the address is never
  4143.           NULL).  If your FLDdestruct function returns something
  4144.           other than zero, FLdelete will then call FLclear to
  4145.           destruct the FlexNodes and if that is successful,
  4146.           FLdelete then frees the dynamically allocated FlexList. 
  4147.           If you FLDdestruct function returns zero then FLdelete
  4148.           will return zero.
  4149.  
  4150.           MaxNodes is set to FLmaxMaxNodes, the maximum allowed
  4151.           for any FlexList which is UINT_MAX (the largest value
  4152.           of an unsigned integer).
  4153.  
  4154.           The sizeofNodeData field within the FlexList header is
  4155.           always zero for variant FlexLists.
  4156.  
  4157. FLvariantNew
  4158.  
  4159.  
  4160. *    Return value
  4161.  
  4162.           If successful, FLvariantNew returns a pointer to a
  4163.           dynamically allocated FlexList, otherwise it returns
  4164.           FlexL0 which is defined in flexlist.h as (FlexL) 0.
  4165.  
  4166. *    Remarks
  4167.  
  4168.           If your dynamic FlexList doesn't need to store data in
  4169.           the FlexList header then pass zero to the
  4170.           sizeofLocalData parameter.
  4171.  
  4172.           If your application doesn't require a FLDdestruct
  4173.           function call FLfixedNew with the NULL pointer
  4174.           constant, FLDdestruct0, defined in flexlist.h.
  4175.  
  4176.           If your dynamic FlexList doesn't store data in the
  4177.           FlexList header, don't access data with FLData! 
  4178.           Likewise if you do specify a FLDdestruct function, be
  4179.           sure your function ignores the local data parameter
  4180.           passed to it!  A Flexlist doesn't maintain a
  4181.           sizeofLocalData field from which it can ascertain
  4182.           whether or not you store any data in the FlexList
  4183.           header.  This was a design consideration to save space
  4184.           in the header.
  4185.  
  4186.           Use FLData and FLisVariant to determine if a FlexList
  4187.           was constructed with FLvariantNew.  FLData returns true
  4188.           for dynamically allocated FlexLists.
  4189.  
  4190.           Be sure to read the previous entry for FLvariant to
  4191.           gain an understanding of how variant FlexLists operate.
  4192.  
  4193. *    See Also
  4194.  
  4195.           FLData, FLdelete, FLisVariant, FLvariant, FLfixed
  4196.  
  4197. *    Example
  4198.  
  4199.           This program builds a list of C strings and then
  4200.           aliases it.  When FLdelete is called it won't destruct
  4201.           the FlexList until all references to it are destructed. 
  4202.           The link count is maintained in the header of the
  4203.           dynamically allocated FlexList.
  4204.  
  4205. FLvariantNew
  4206.  
  4207.  
  4208.           #include <stdio.h>       /*  printf()  */
  4209.           #include <string.h>      /*  strcmp()  */
  4210.           #include <flexlist.h>    /*  FlexL0, FLcomparE */
  4211.                                    /*  FlexNodeStrVFT  */
  4212.  
  4213.           FlexL FLlinkInit(FlexL L)
  4214.           {
  4215.                int *links;
  4216.  
  4217.                if ((links = FLData(L)) != (int *) 0)
  4218.                     *links = 1;
  4219.                return L;
  4220.           }
  4221.  
  4222.           FlexL FLlink(FlexL L)
  4223.           {
  4224.                int *links;
  4225.  
  4226.                if ((links = FLData(L)) != (int *) 0)
  4227.                     ++*links;
  4228.                return L;
  4229.           }
  4230.  
  4231.           int FLunlinked(void *LD)
  4232.           {  /*  LD is never NULL!  */
  4233.                int *links = (int *) LD;
  4234.  
  4235.                if (--*links)
  4236.                     return 0;
  4237.                return 1;
  4238.           }
  4239.  
  4240.           main()
  4241.           {
  4242.                FlexL L1, L2;
  4243.                char s[80];
  4244.  
  4245.                if ((L1 = FLlinkInit(FLvariantNew(&FlexNodeStrVFT,
  4246.                     sizeof(int),FLunlinked))) == FlexL0)
  4247.                     return 1;
  4248.                FLinsQD(L1,"one dog");   /* calls FNnew */
  4249.                FLinsQD(L1,"two cats");
  4250.                L2 = FLlink(L1);
  4251.                FLinsQD(L2,"three crows");
  4252. FLvariantNew
  4253.  
  4254.  
  4255.                while (FLnextD(L1,s))  /* calls FNread */
  4256.                     printf("\n%s",s);
  4257.                FLstoreD(L2,"three cat birds",FLnodes(L2)); 
  4258.                     /* calls FNwrite which truncates!  */
  4259.                FLdelete(&L1);  /*  FLdelete fails  */
  4260.                printf("\nNodes in L1: %u",FLnodes(L1));
  4261.                FLsort(L1,FLcomparE(strcmp));
  4262.                FLmkcur(L2,0);
  4263.                while (FLnextD(L2,s))  
  4264.                     printf("\n%s",s);
  4265.                FLdelete(&L2);  /*  Fldelete succeeds  */
  4266.                /* L2 is NULL now but not L1  */
  4267.                L1 = FlexL0;
  4268.                printf("\nNodes in L2: %u",FLnodes(L2));
  4269.                return 0;
  4270.           }
  4271.  
  4272.           FLdelete has to be called twice to decrement the link
  4273.           counter in the FlexList header via FLunlinked, the user
  4274.           defined FLDdestruct function.
  4275.  
  4276.           I skipped listing the virtual function definitions. 
  4277.           You can see them in the section on FLvariant or in the
  4278.           flexlist.c source file.
  4279.  
  4280.           FlexNodeStrVFT is the virtual function table that
  4281.           contains pointers to the virtual functions that handle
  4282.           C strings.
  4283.  
  4284.           The FLcomparE macro, defined in flexlist.h, is used to
  4285.           precisely type cast the user function pointer to the
  4286.           type required by both FLsort and FLsetCompare.
  4287. Appendix A.  Common Mistakes       
  4288.  
  4289.  
  4290. Some common coding mistakes are listed below.
  4291.  
  4292. 1.   If you pass an address to a FlexList function of an item
  4293.      other than the type for which the FlexList was constructed
  4294.      for, data could be corrupted or the program may crash. 
  4295.      Suppose you call FLpopD with the address of a local variable
  4296.      of the wrong type.  If this variable is shorter in length
  4297.      than what the FlexList expects, other data on C's stack
  4298.      would be corrupted, perhaps the return address from that
  4299.      function.  If the FlexList functions were prototyped for
  4300.      strong type checking, i.e. something other than "void *", to
  4301.      avoid this, they would no longer be generic.  Moral: you
  4302.      must insure that the correct data types are used with their
  4303.      respective FlexLists.
  4304.  
  4305. 2.   If the item itself, instead of its address, is passed to the
  4306.      FlexList function, the item's contents will be wrongly
  4307.      interpreted as the address to write to or read from.  This
  4308.      would result in writing good data to a wrong address or
  4309.      copying garbage from a wrong address.  This is obviously
  4310.      undesirable!
  4311.  
  4312. 3.   It's sometimes easy to forget that the FLfixed, etc.,
  4313.      constructor functions take the "sizeof" a type/variable
  4314.      instead of a variable of that type.  The compiler won't
  4315.      catch it when your "FlexListing" integer types.  The
  4316.      FlexList will be wrongly initialized for the size of the
  4317.      integer variable's value instead of the sizeof(integer
  4318.      variable).
  4319.  
  4320. 4.   If your FNwrite virtual function, used with a variant
  4321.      FlexList, overwrites the end of the FlexNode it will corrupt
  4322.      other dynamically allocated memory.  There is a remote
  4323.      possibility that it may overwrite the C stack depending on
  4324.      how your C compiler sets up the heap and stack.
  4325.  
  4326. 5.   With variant FlexLists, if the location you are copying data
  4327.      to from a FlexNode isn't big enough to accommodate the
  4328.      largest possible variant data, it of course will spill over
  4329.      into other variables.  If the location is a local variable,
  4330.      the C stack will be corrupted with the results mentioned in
  4331.      1 above.
  4332.  
  4333. 6.   When porting FlexList to various machines malloc can't
  4334.      always allocate the full size of the maximum value that a
  4335.      size_t variable can obtain.  Be sure that FLmallocAlignLoss,
  4336.      defined near the bottom of flexlist.h, is defined
  4337.      appropriately. Appendix B.Inside FlexList
  4338.  
  4339.  
  4340. A FlexList has two data structures that provide the basis for all
  4341. operations.
  4342.  
  4343. 1.   A FlexNode has both next and previous FlexNode pointers. 
  4344. The user data area is a character array of one byte.  Actually
  4345. this field varies in length according to the value in the
  4346. sizeofNodeData field depicted in the FlexList header or as
  4347. determined by your FNnew virtual function.  The void pointers
  4348. returned by FlexList functions point to the first byte of this
  4349. character array.
  4350.                            ┌────────┐
  4351.        FlexNode            │  next  ├────>
  4352.                            ├────────┤   
  4353.                       <────┤  prev  │
  4354.                            ├────────┤  
  4355.                            │  data  │     char [1]
  4356.                            └────────┘
  4357.  
  4358. 2.   The FlexList header contains data for controlling the list.
  4359.  
  4360.           FlexList
  4361.         ┌────────────────┐
  4362.         │ front          │ ───> points to first FlexNode in list
  4363.         ├────────────────┤
  4364.         │ current        │ ───> points to last FlexNode accessed
  4365.         ├────────────────┤
  4366.         │ rear           │ ───> points to last FlexNode in list
  4367.         ├────────────────┤
  4368.         │ curNum         │      number of the current FlexNode
  4369.         ├────────────────┤
  4370.         │ nodes          │      number of FlexNodes in list
  4371.         ├────────────────┤
  4372.         │ maxNodes       │      maximum FlexNodes allowed
  4373.         ├────────────────┤
  4374.         │ sizeofNodeData │      size of data in FlexNodes
  4375.         ├────────────────┤
  4376.         │ sizeofNode     │      size of FlexNodes with data
  4377.         ├────────────────┤
  4378.         │ sorted         │      is the FlexList sorted
  4379.         ├────────────────┤
  4380.         │ compare        │      function used to sort/match
  4381.         ├────────────────┤
  4382.         │ vft            │ ───> virtual function table
  4383.         ├────────────────┤
  4384.         │ FLDdestruct    │      destructor function for data
  4385.         ├────────────────┤
  4386.         │ data           │      0 length unless user defined
  4387.         └────────────────┘ Consider the code listing below and the resultant data structure
  4388. from having executed this code.  Several non pertinent fields of
  4389. the FlexList header have been left out of the figure.
  4390.  
  4391.  
  4392.      {
  4393.           FlexList l;
  4394.           int i = 45;
  4395.  
  4396.           FLfixed(&l,sizeof(int));
  4397.           FLpushD(&l,&i);
  4398.           i = 37;
  4399.           FLinsQD(&l,&i);
  4400.           FLmkcur(&l,1);
  4401.           i = 29;
  4402.           FLinsD(&l,&i);
  4403.      }        
  4404.  
  4405.  
  4406.      FlexList         ┌─────────────────────┐          FlexNode
  4407.                       │                     ■
  4408.    ┌───────────────┐  │     ┌──────┐     ┌──────┐    ┌──────┐
  4409.    │ front         ├──┼────■│ next ├────■│ next ├───■│ next ├───┐
  4410.    ├───────────────┤  │     ├──────┤     ├──────┤    ├──────┤   ■
  4411.    │ current       ├──┘  ┌──┤ prev │■────┤ prev │■───┤ prev │
  4412.    ├───────────────┤     ■  ├──────┤     ├──────┤    ├──────┤
  4413.    │ rear          ├──┐     │  45  │     │  29  │    │  37  │
  4414.    ├───────────────┤  │     └──────┘     └──────┘    └──────┘
  4415.    │ curNum      2 │  │                                  ■   
  4416.    ├───────────────┤  └──────────────────────────────────┘   
  4417.    │ nodes       3 │   
  4418.    ├───────────────┤  
  4419.    │ sizeofN.D.  2 │  
  4420.    ├───────────────┤
  4421.    │ sizeofNode  6 │  ( 2 byte pointers )
  4422.    ├───────────────┤
  4423.    │ vft           ├──┐
  4424.    └───────────────┘  │
  4425.                       ■  (NULL)
  4426.  
  4427. The FlexList functions use the data in the FlexList header to
  4428. adjust their various operations, e.g. allocating, copying,
  4429. deallocating, etc., for the type of data that is being
  4430. warehoused.
  4431. Consider the code listing below and the resultant data structure
  4432. from having executed this code.  Several non pertinent fields of
  4433. the FlexList header have been left out of the figure.
  4434.  
  4435.  
  4436.      {
  4437.           FlexList l;
  4438.  
  4439.           FLstr(&l);
  4440.           FLinsD(&l,"flex");
  4441.           FLpushD(&l,"Hello");
  4442.           FLinsQD(&l,"world!");
  4443.      }        
  4444.  
  4445.  
  4446.      FlexList         ┌─────────────────────┐          FlexNode
  4447.                       │                     ■
  4448.    ┌───────────────┐  │     ┌──────┐     ┌──────┐    ┌──────┐
  4449.    │ front         ├──┼────■│ next ├────■│ next ├───■│ next ├───┐
  4450.    ├───────────────┤  │     ├──────┤     ├──────┤    ├──────┤   ■
  4451.    │ current       ├──┘  ┌──┤ prev │■────┤ prev │■───┤ prev │
  4452.    ├───────────────┤     ■  ├──────┤     ├──────┤    ├──────┤
  4453.    │ rear          ├──┐     │   H  │     │   f  │    │   w  │
  4454.    ├───────────────┤  │     │   e  │     │   l  │    │   o  │
  4455.    │ curNum      2 │  │     │   l  │     │   e  │    │   r  │
  4456.    ├───────────────┤  │     │   l  │     │   x  │    │   l  │
  4457.    │ nodes       3 │  │     │   o  │     │  \0  │    │   d  │
  4458.    ├───────────────┤  │     │  \0  │     └──────┘    │   !  │
  4459.    │ sizeofN.D.  0 │  │     └──────┘                 │  \0  │
  4460.    ├───────────────┤  │                              └──────┘
  4461.    │ sizeofNode  0 │  │                                  ■
  4462.    ├───────────────┤  └──────────────────────────────────┘
  4463.    │ vft           ├──┐
  4464.    └───────────────┘  │    FlexNodeVFT
  4465.                       │
  4466.                       │   ┌────────────┐
  4467.                       └──■│ FNnew      │
  4468.                           ├────────────┤
  4469.                           │ FNwrite    │
  4470.                           ├────────────┤
  4471.                           │ FNread     │
  4472.                           ├────────────┤
  4473.                           │ FNdestruct │
  4474.                           └────────────┘
  4475.  
  4476.  
  4477. The FlexList functions use the FlexNodeVFT function pointers to
  4478. handle the variant length C strings, e.g. allocating, copying,
  4479. deallocating, etc.
  4480. Consider the code listing below and the resultant data structure
  4481. from having executed this code.
  4482.  
  4483.      {
  4484.           FlexL L;
  4485.  
  4486.           L = FLfixedNew(sizeof(int),strlen("Hello")+1,
  4487.                     FLDdestruct0);
  4488.           if (L)
  4489.                strcpy(FLData(L),"Hello");
  4490.      }
  4491.  
  4492.               FlexList
  4493.         ┌───────────────────┐
  4494.         │ front             ├────────────┐
  4495.         ├───────────────────┤            │
  4496.         │ current           ├───────┐    ■
  4497.         ├───────────────────┤       │
  4498.         │ rear              ├────┐  ■
  4499.         ├───────────────────┤    │
  4500.         │ curNum          0 │    ■
  4501.         ├───────────────────┤
  4502.         │ nodes           0 │
  4503.         ├───────────────────┤
  4504.         │ maxNodes    65535 │    largest unsigned ( 2 bytes )
  4505.         ├───────────────────┤
  4506.         │ sizeofNodeData  2 │    ( 2 byte ints )
  4507.         ├───────────────────┤
  4508.         │ sizeofNode      6 │    ( 2 byte pointers)
  4509.         ├───────────────────┤ 
  4510.         │ sorted          1 │    zero nodes are always sorted!
  4511.         ├───────────────────┤
  4512.         │ compare           ├───────────┐
  4513.         ├───────────────────┤           │
  4514.         │ vft               ├───────┐   ■
  4515.         ├───────────────────┤       │
  4516.         │ FLDdestruct       ├────┐  ■
  4517.         ├───────────────────┤    │
  4518.         │       H           │    ■
  4519.         │       e           │
  4520.         │       l           │
  4521.         │       l           │
  4522.         │       o           │
  4523.         │      \0           │
  4524.         └───────────────────┘
  4525.  
  4526.  
  4527. The FlexList header itself can be enlarged to hold additional
  4528. data pertinent to the list overall.  FLdelete calls your
  4529. FLDdestruct function with the starting address of "Hello" in this
  4530. case.
  4531. Appendix C.   FlexList Source Code
  4532.  
  4533.  
  4534. /*
  4535.      flexlist.h
  4536.      10-4-90
  4537.      Homogeneous-heterogeneous 
  4538.      hybrid stack-queue-list-array generic class.
  4539.      ANSI C
  4540.  
  4541.      Copyright 1990
  4542.      John W. Small
  4543.      All rights reserved
  4544.  
  4545.      PSW / Power SoftWare
  4546.      P.O. Box 10072
  4547.      McLean, Virginia 22102 8072
  4548.      (703) 759-3838
  4549. */
  4550.  
  4551. /* LINTLIBRARY */
  4552.  
  4553. #ifndef FLEXLIST_ANSI_C
  4554. #define FLEXLIST_ANSI_C
  4555.  
  4556. #include <stddef.h> /*  size_t  */
  4557. #include <limits.h> /*  UINT_MAX  */
  4558.  
  4559.  
  4560. /*  FlexNode declarations  */
  4561.  
  4562. typedef struct FlexNode_ FlexNode, *FlexN;
  4563. #define FlexN0 ((FlexN)0)
  4564. #define FlexNodeLinkage FlexN next, prev
  4565.  
  4566. struct FlexNode_ {
  4567. /*  friend: FlexList  */
  4568.      FlexNodeLinkage;
  4569. /*  public:  */
  4570.      char data[1];
  4571. };
  4572.  
  4573. /*  Virtual functions for variant FlexNodes  */
  4574.  
  4575. typedef struct  {
  4576. /*  friend: FlexList  */
  4577.      FlexN (*FNnew)(const void *D);
  4578.      int   (*FNwrite)(void *ND, const void *D);
  4579.      int   (*FNread)(const void *ND, void *D);
  4580.      int   (*FNdestruct)(void *ND, void *D);
  4581. } FlexNodeVFT, *FlexNVFT;
  4582.  
  4583. #define FlexNVFT0 ((FlexNVFT)0)
  4584. #define FNnew0 ((FlexN (*)(const void *D)) 0)
  4585. #define FNwrite0 ((int (*)(void *ND, const void *D)) 0)
  4586. #define FNread0 ((int (*)(const void *ND, void *D)) 0)
  4587. #define FNdestruct0 ((int (*)(void *ND, void *D)) 0)
  4588.  
  4589. /*  String variant FlexNode functions  */
  4590. extern  FlexNodeVFT FlexNodeStrVFT;
  4591.  
  4592. /*  FlexList header declaration  */
  4593.  
  4594. typedef struct  {
  4595. /*  private:  */
  4596.      FlexN  front, current, rear;
  4597.      unsigned curNum, nodes, maxNodes;
  4598.      size_t sizeofNodeData, sizeofNode;
  4599.      int sorted;
  4600.      int (*compare)(const void *D1, const void *D2);
  4601.      FlexNVFT vft;
  4602.      int (*FLDdestruct)(void *LD);
  4603.      char data[1];
  4604. } FlexList, *FlexL;
  4605.  
  4606. #define FlexL0 ((FlexL)0)
  4607. #define FLcomparE(compare)  ((int (*)(const void *D1, \
  4608.           const void *D2)) compare)
  4609. #define FLcompare0  FLcomparE(0)
  4610. #define FLDdestruct0 ((int (*)(void *LD)) 0)
  4611.  
  4612.  
  4613. /*  FlexList constructors/destructor - static headers  */
  4614. extern  FlexL FLfixed(FlexL L, size_t sizeofNodeData);
  4615. extern  FlexL FLunpack(FlexL L, size_t sizeofCell, 
  4616.           unsigned cells, const void *array);
  4617. extern  FlexL FLvariant(FlexL L, FlexNVFT vft);
  4618. #define FLstr(L) FLvariant(L,&FlexNodeStrVFT)
  4619. extern  int   FLclear(FlexL L);
  4620.  
  4621. /*  FlexList constructors/destructor - dynamic headers  */
  4622. extern  FlexL FLfixedNew(size_t sizeofNodeData,
  4623.           size_t sizeofLocalData, 
  4624.           int (*FLDdestruct)(void *LD));
  4625. extern  FlexL FLunpackNew(size_t sizeofCell, 
  4626.           unsigned cells, const void *array,
  4627.           size_t sizeofLocalData,
  4628.           int (*FLDdestruct)(void *LD));
  4629. extern  FlexL FLvariantNew(FlexNVFT vft,
  4630.           size_t sizeofLocalData, 
  4631.           int (*FLDdestruct)(void *LD));
  4632. #define FLstrNew(sizeofLocalData, FLDdestruct)  \
  4633.           FLvariantNew(&FlexNodeStrVFT,  \
  4634.                sizeofLocalData,FLDdestruct)
  4635. extern  int   FLdelete(FlexL *Lptr);
  4636.  
  4637. /*  FlexList header functions  */
  4638. #define FLfrontD(L) (void *)((L)? (L)->front? \
  4639.           (L)->front->data : 0 : 0)
  4640. #define FLcurrentD(L) (void *)((L)? (L)->current? \
  4641.           (L)->current->data : 0 : 0)
  4642. #define FLrearD(L) (void *)((L)? (L)->rear? \
  4643.           (L)->rear->data : 0 : 0)
  4644. #define FLcurNum(L) ((L)? (L)->curNum : 0)
  4645. #define FLnodes(L)  ((L)? (L)->nodes : 0)
  4646. #define FLmaxNodes(L) ((L)? (L)->maxNodes : 0)
  4647. extern  int   FLsetMaxNodes(FlexL L, unsigned maxNodes);
  4648. #define FLnotFull(L) ((L)? ((L)->maxNodes - (L)->nodes) : 0)
  4649. #define FLsizeofNodeData(L) ((L)? (L)->sizeofNodeData : 0)
  4650. #define FLisSorted(L)  ((L)? (L)->sorted : 0)
  4651. #define FLunSort(L)  ((L)? ((L)->sorted = 0, 1) : 0)
  4652. #define FLcompare(L)  ((L)? (L)->compare : FLcompare0)
  4653. extern  int   FLsetCompare(FlexL L, int (*compare)
  4654.           (const void *D1, const void *D2));
  4655. #define FLisFixed(L)  FLsizeofNodeData(L)
  4656. #define FLisVariant(L) ((L)? !((L)->sizeofNodeData):0)
  4657. #define FLData(L)  (void *)((L)? ((L)->FLDdestruct?  \
  4658.           (L)->data : 0) : 0)
  4659.  
  4660. /*  FlexList stack and queue functions  */
  4661. extern  void *FLpushN(FlexL L, FlexN N);
  4662. extern  void *FLpushD(FlexL L, const void *D);
  4663. extern  FlexN FLpopN(FlexL L);
  4664. extern  int   FLpopD(FlexL L, void *D);
  4665. extern  void *FLtopD(FlexL L, void *D);
  4666. extern  void *FLinsQN(FlexL L, FlexN N);
  4667. extern  void *FLinsQD(FlexL L, const void *D);
  4668.  
  4669. /*  FlexList list functions  */
  4670. extern  void *FLmkcur(FlexL L, unsigned n);
  4671. extern  void *FLinsN(FlexL L, FlexN N);
  4672. extern  void *FLinsD(FlexL L, const void *D);
  4673. extern  void *FLinsSortN(FlexL L, FlexN N);
  4674. extern  void *FLinsSortD(FlexL L, const void *D);
  4675. extern  FlexN FLdelN(FlexL L);
  4676. extern  int   FLdelD(FlexL L, void *D);
  4677. extern  void *FLnextD(FlexL L, void *D);
  4678. extern  void *FLprevD(FlexL L, void *D);
  4679.  
  4680. /*  FlexList search/sort functions  */
  4681. /*  See also FLinsSortN()/FLinsSortD() list functions  */
  4682. extern  void *FLfindFirstD(FlexL L, const void *D);
  4683. extern  void *FLfindNextD(FlexL L, const void *D);
  4684. extern  void *FLfindLastD(FlexL L, const void *D);
  4685. extern  void *FLfindPrevD(FlexL L, const void *D);
  4686. extern  int   FLsort(FlexL L, int (*compare)
  4687.           (const void *D1, const void *D2));
  4688.  
  4689. /*  FlexList array functions  */
  4690. /*  See also compaction functions */
  4691. extern  int   FLstoreD(FlexL L, const void *D, unsigned n);
  4692. extern  int   FLrecallD(FlexL L, void *D, unsigned n);
  4693.  
  4694. /*  FlexList compaction functions  */
  4695. /*  See also FLunpack()/FLunpackNew() constructors  */
  4696. extern  void *FLpack(FlexL L);
  4697. extern  void **FLpackPtrs(FlexL L);
  4698.  
  4699. /*  FlexList implementation constants  */
  4700. /*  Change as required by target machine  */
  4701. #define FLmaxMaxNodes  UINT_MAX
  4702. #define FLmallocAlignLoss  16
  4703. #define FLmaxSizeofLocalData \
  4704.      ((size_t)(-(long)sizeof(FlexList) \
  4705.      -FLmallocAlignLoss))
  4706. #define FLmaxSizeofNodeData  \
  4707.      ((size_t)(-(long)sizeof(FlexNode) \
  4708.      -FLmallocAlignLoss))
  4709. #define FLmaxSizeofArray \
  4710.      ((long)(size_t)-FLmallocAlignLoss)
  4711.  
  4712. #endif
  4713. /*
  4714.  
  4715.      flexlist.c
  4716.      10-4-90
  4717.      Homogeneous-heterogeneous 
  4718.      hybrid stack-queue-list-array generic class.
  4719.      ANSI C
  4720.  
  4721.      Copyright 1990
  4722.      John W. Small
  4723.      All rights reserved
  4724.  
  4725.      PSW / Power SoftWare
  4726.      P.O. Box 10072,
  4727.      McLean, Virginia 22102 8072
  4728.      (703) 759-3838
  4729.  
  4730. */
  4731.  
  4732.  
  4733. #include <flexlist.h>    /*  <stddef.h>  size_t  */
  4734. #include <stdlib.h>      /*  malloc(), free()    */
  4735. #include <string.h>      /*  memcpy(), memset()  */
  4736.  
  4737.  
  4738. /*  String variant FlexNode virtual functions  */
  4739.  
  4740. /*
  4741.      FNnew() is called by FlexList functions (primitives)
  4742.      that need to allocate new variant length FlexNodes,
  4743.      e.g. FLpushD(), FLinsQD(), FLinsD(), FLinsSortD().
  4744.      A pointer to the data to be placed in the new node
  4745.      is passed to FNnew().  Your FNnew() function must
  4746.      decide how large that data is and allocate a new 
  4747.      FlexNode big enough to hold that data, i.e.
  4748.  
  4749.      FlexN N = malloc(sizeof(FlexNode) + 
  4750.          sizeofYourData - 1).
  4751.  
  4752.      Your FNnew() function must also copy that data to
  4753.      the new node.  "D" is never NULL!
  4754.  
  4755.      Please note that FNnew() could call a known function
  4756.      pointer (function) in the data to determine its size.
  4757.      It could also call another function to copy/
  4758.      initialize the FlexNode data area from the data.
  4759.      Data that contains its own functions for interfacing 
  4760.      with itself are called objects.  Thus FlexLists can 
  4761.      be made to hold polymorphic objects via the 
  4762.      virtual function table functionology.
  4763.  
  4764.      Study all four virtual functions FNnew(), FNwrite(),
  4765.      FNread(), and FNdestruct() for strings and how they
  4766.      are called by the various FlexList functions to get
  4767.      a better understanding of variant FlexLists.
  4768. */
  4769.  
  4770. static FlexN FNnewStr(const void *D)
  4771. {
  4772.      FlexN N;
  4773.      size_t i;
  4774.  
  4775.      for (i = 0; ((char *)D)[i++]; /* no reinit */)
  4776.           /* null statement */;
  4777.      if ((N = malloc(sizeof(FlexNode)+i-1)) != FlexN0)
  4778.           (void) memcpy(N->data,D,i);
  4779.      return N;
  4780. }
  4781.  
  4782.  
  4783. /*  FNwrite() is called by FLstoreD() to write variant data
  4784.      to a variant FlexNode.  Make sure the new data 
  4785.      doesn't write pass the end of the old.  FNwrite()
  4786.      returns true if the write is successful.  "ND" and
  4787.      "D" are never NULL! */
  4788.  
  4789. static int FNwriteStr(void *ND, const void *D)
  4790. {
  4791.      char *nd, *d;
  4792.      
  4793.      nd = (char *) ND;
  4794.      d = (char *) D;
  4795.      while (*nd)
  4796.           if ((*nd++ = *d++) == '\0')
  4797.                break;
  4798.      return 1;
  4799. }
  4800.  
  4801. /*  FNread() is called by FLtopD(), FLnextD(), 
  4802.      FLprevD(), and FLrecallD() to read variant data
  4803.      from a variant FlexNode.  FNread() returns true if
  4804.      the read is successful.  "ND" and "D" are never 
  4805.      NULL!  */
  4806.  
  4807. static int FNreadStr(const void *ND, void *D)
  4808. {
  4809.      char *nd, *d;
  4810.      
  4811.      nd = (char *) ND;
  4812.      d = (char *) D;
  4813.      while ((*d++ = *nd++) != '\0')
  4814.           /* null statement */;
  4815.      return 1;
  4816. }
  4817.  
  4818. /*  FNdestruct() is called by FLclear(), FLdelete() via 
  4819.      Flclear(), FLpopD(), and FLdelD() to destruct
  4820.      variant data in a FlexNode.  Please note that
  4821.      references to suballocated memory may be copied
  4822.      to the outgoing data structure instead of being
  4823.      cloned and then deallocated.  You must keep any
  4824.      scheme straight though.  FLclear() always passes
  4825.      NULL to the second parameter of FNdestruct() via
  4826.      a call to FLpopD(L,0),   however, so any 
  4827.      suballocated memory must be freed in that case!
  4828.      "ND" is never NULL but "D" can be!  */
  4829.  
  4830. static int FNdestructStr(void *ND, void *D)
  4831. {
  4832.      char *nd, *d;
  4833.      
  4834.      nd = (char *)ND;
  4835.      if ((d = (char *)D) != (char *)0) 
  4836.           while ((*d++ = *nd++) != '\0')
  4837.                /* null statement */;
  4838.      return 1;
  4839. }
  4840.  
  4841. /*  Any of the virtual functions can be absent.  The FlexList
  4842.      functions that call them will simply return a failure
  4843.      indication.  Use FNnew0, FNwrite0, FNread0, and/or
  4844.      FNdestruct0 as zero initializers.  */
  4845.  
  4846. FlexNodeVFT FlexNodeStrVFT = { 
  4847.      FNnewStr, FNwriteStr, FNreadStr, FNdestructStr };
  4848.  
  4849.  
  4850. /*  FlexList constructors/destructor - static headers */
  4851.  
  4852.  
  4853. #define FLzero(L) memset((void *)(L),0,sizeof(FlexList)-1)
  4854.  
  4855. FlexL FLfixed(FlexL L, size_t sizeofNodeData)
  4856. {
  4857.      if (!L)  
  4858.           return L;
  4859.      (void) FLzero(L);
  4860.      if (!sizeofNodeData || sizeofNodeData 
  4861.           > FLmaxSizeofNodeData)
  4862.           return FlexL0;
  4863.      L->maxNodes = FLmaxMaxNodes;
  4864.      L->sizeofNodeData = sizeofNodeData;
  4865.      L->sizeofNode = sizeof(FlexNode) 
  4866.           + sizeofNodeData - 1;
  4867.      L->sorted = 1;
  4868.      return L;
  4869. }
  4870.  
  4871. FlexL FLunpack(FlexL L, size_t sizeofCell, 
  4872.      unsigned cells, const void *array)
  4873. {
  4874.      if (!L) 
  4875.           return L;
  4876.      (void) FLzero(L);
  4877.      if ((sizeofCell > FLmaxSizeofNodeData) ||
  4878.           !sizeofCell || !cells || !array)
  4879.           return FlexL0;
  4880.      L->maxNodes = FLmaxMaxNodes;
  4881.      L->sizeofNodeData = sizeofCell;
  4882.      L->sizeofNode = sizeof(FlexNode) 
  4883.           + sizeofCell - 1;
  4884.      for (;cells && FLinsQD(L,array); cells--)
  4885.           array = (char *) array + sizeofCell;
  4886.      return L;
  4887. }
  4888.  
  4889. FlexL FLvariant(FlexL L, FlexNVFT vft)
  4890. {
  4891.      if (!L)
  4892.           return L;
  4893.      (void) FLzero(L);
  4894.      if (!vft)
  4895.           return FlexL0;
  4896.      L->maxNodes = FLmaxMaxNodes;
  4897.      L->sorted = 1;
  4898.      L->vft = vft;
  4899.      return L;
  4900. }
  4901. int   FLclear(FlexL L)
  4902. {
  4903.      while (FLpopD(L,(void *)0))
  4904.           /* null statement */;
  4905.      if (L) if (!L->nodes)
  4906.           return (L->sorted = 1);
  4907.      return 0;
  4908. }
  4909.  
  4910. /*  FlexList constructors/destructor - dynamic headers  */
  4911.  
  4912. /*  FlexList headers are flagged as dynamic if and only if
  4913.      FLDdestruct != NULL.  FLDmalloced() is the default
  4914.      function pointer whenever one isn't specified.  */
  4915. #pragma argsused
  4916. /* ARGSUSED */ 
  4917. static int FLDmalloced(void *LD)
  4918. {    /*  LD is intentionally unused!  */
  4919.      return 1;
  4920. }
  4921.  
  4922. static FlexL FLnew(size_t sizeofLocalData, 
  4923.      int (*FLDdestruct)(void *LD))
  4924. {
  4925.      FlexL L;
  4926.  
  4927.      if (sizeofLocalData > FLmaxSizeofLocalData) 
  4928.           return FlexL0;
  4929.      L = (FlexL) malloc(sizeof(FlexList) + 
  4930.           sizeofLocalData - 1);
  4931.      if (L)  {
  4932.           (void) FLzero(L);
  4933.           if (FLDdestruct)
  4934.                L->FLDdestruct = FLDdestruct;
  4935.           else
  4936.                L->FLDdestruct = FLDmalloced;
  4937.      }
  4938.      return L;
  4939. }
  4940.  
  4941. FlexL FLfixedNew(size_t sizeofNodeData,
  4942.      size_t sizeofLocalData, 
  4943.      int (*FLDdestruct)(void *LD))
  4944. {
  4945.      FlexL L;
  4946.  
  4947.      if (!sizeofNodeData || sizeofNodeData > 
  4948.           FLmaxSizeofNodeData) 
  4949.           return FlexL0;
  4950.      if ((L = FLnew(sizeofLocalData,FLDdestruct)) 
  4951.           != FlexL0)  {
  4952.           L->maxNodes = FLmaxMaxNodes;
  4953.           L->sizeofNodeData = sizeofNodeData;
  4954.           L->sizeofNode = sizeof(FlexNode) 
  4955.                + sizeofNodeData - 1;
  4956.           L->sorted = 1;
  4957.      }
  4958.      return L;
  4959. }
  4960.  
  4961. FlexL FLunpackNew(size_t sizeofCell, 
  4962.      unsigned cells, const void *array,
  4963.      size_t sizeofLocalData,
  4964.      int (*FLDdestruct)(void *LD))
  4965. {
  4966.      FlexL L;
  4967.  
  4968.      if ((sizeofCell > FLmaxSizeofNodeData) ||
  4969.           !sizeofCell || !cells || !array)
  4970.           return FlexL0;
  4971.      if ((L = FLnew(sizeofLocalData,FLDdestruct)) 
  4972.           != FlexL0)  {
  4973.           L->maxNodes = FLmaxMaxNodes;
  4974.           L->sizeofNodeData = sizeofCell;
  4975.           L->sizeofNode = sizeof(FlexNode) 
  4976.                + sizeofCell - 1;
  4977.           for (;cells && FLinsQD(L,array); cells--)
  4978.                array = (char *) array + sizeofCell;
  4979.      }
  4980.      return L;
  4981. }
  4982.  
  4983. FlexL FLvariantNew(FlexNVFT vft,
  4984.      size_t sizeofLocalData,
  4985.      int (*FLDdestruct)(void *LD))
  4986. {
  4987.      FlexL L;
  4988.  
  4989.      if (!vft) 
  4990.           return FlexL0;
  4991.      if ((L = FLnew(sizeofLocalData,FLDdestruct)) 
  4992.           != FlexL0)  {
  4993.           L->maxNodes = FLmaxMaxNodes;
  4994.           L->sorted = 1;
  4995.           L->vft = vft;
  4996.      }
  4997.      return L;
  4998. }
  4999.  
  5000. int FLdelete(FlexL *Lptr)
  5001. {
  5002.      if (!Lptr) 
  5003.           return 0;
  5004.      if (!(*Lptr)->FLDdestruct) 
  5005.           return 0;
  5006.      if (!(*((*Lptr)->FLDdestruct))((*Lptr)->data))
  5007.           return 0;
  5008.      if (!FLclear(*Lptr)) 
  5009.           return 0;
  5010.      free(*Lptr); 
  5011.      *Lptr = FlexL0;
  5012.      return 1;
  5013. }
  5014.  
  5015.  
  5016. /*  FlexList header functions  */
  5017.  
  5018. int FLsetMaxNodes(FlexL L, unsigned maxNodes)
  5019. {
  5020.      if (L)
  5021.           if (maxNodes >= L->nodes)  {
  5022.                L->maxNodes = maxNodes;
  5023.                return 1;
  5024.           }
  5025.      return 0;
  5026. }
  5027.  
  5028. int FLsetCompare(FlexL L, int (*compare)
  5029.      (const void *D1, const void *D2))
  5030. {
  5031.      if (L)  {
  5032.           L->compare = compare;
  5033.           L->sorted = 0;
  5034.           return 1;
  5035.      }
  5036.      return 0;
  5037. }
  5038.  
  5039.  
  5040. /*  FlexList stack and queue functions  */
  5041.  
  5042. void * FLpushN(FlexL L, FlexN N)
  5043. {
  5044.      if (!L || !N) 
  5045.           return (void *) 0;
  5046.      if (L->nodes >= L->maxNodes)  
  5047.           return (void *) 0;
  5048.      N->prev = FlexN0;
  5049.      if ((N->next = L->front) != FlexN0)
  5050.           N->next->prev = N;
  5051.      else
  5052.           L->rear = N;
  5053.      L->front = N;
  5054.      L->nodes++;
  5055.      if (L->curNum) 
  5056.           L->curNum++;
  5057.      L->sorted = 0;
  5058.      return N->data;
  5059. }
  5060.  
  5061. void * FLpushD(FlexL L, const void *D)
  5062. {
  5063.      FlexN N;
  5064.  
  5065.      if (!L) 
  5066.           return (void *) 0;
  5067.      if (L->nodes >= L->maxNodes) 
  5068.           return (void *) 0;
  5069.      if (L->sizeofNode) {  /*  fixed size FlexNodes  */
  5070.           if ((N = malloc(L->sizeofNode)) == FlexN0)
  5071.                return (void *) 0;
  5072.           if (D) 
  5073.                memcpy(N->data,D,L->sizeofNodeData);
  5074.           else
  5075.                memset(N->data,0,L->sizeofNodeData);
  5076.      }
  5077.      else if (!L->vft || !D)
  5078.           return (void *) 0;
  5079.      else if (!L->vft->FNnew)
  5080.           return (void *) 0;
  5081.      else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
  5082.           return (void *) 0;
  5083.      N->prev = FlexN0;
  5084.      if ((N->next = L->front) != FlexN0)
  5085.           N->next->prev = N;
  5086.      else
  5087.           L->rear = N;
  5088.      L->front = N;      
  5089.      L->nodes++;
  5090.      if (L->curNum) 
  5091.           L->curNum++;
  5092.      L->sorted = 0;
  5093.      return N->data;
  5094. }
  5095.  
  5096. FlexN  FLpopN(FlexL L)
  5097. {
  5098.      FlexN N;
  5099.      
  5100.      if (!L) 
  5101.           return FlexN0;
  5102.      if ((N = L->front) == FlexN0)
  5103.           return FlexN0;
  5104.      if (L->front == L->rear)
  5105.           L->rear = FlexN0;
  5106.      else
  5107.           N->next->prev = FlexN0;
  5108.      L->front = N->next;
  5109.      L->nodes--;
  5110.      if (L->curNum)  
  5111.           if (!--L->curNum)
  5112.                L->current = FlexN0;
  5113.      N->next = N->prev = FlexN0;
  5114.      return N;
  5115. }
  5116.  
  5117. int FLpopD(FlexL L, void *D)
  5118. {
  5119.      FlexN N;
  5120.      
  5121.      if (!L) 
  5122.           return 0;
  5123.      if ((N = L->front) == FlexN0)
  5124.           return 0;
  5125.      if (L->sizeofNodeData)  {
  5126.           if (D)
  5127.                memcpy(D,N->data,L->sizeofNodeData);
  5128.      }
  5129.      else if (!L->vft)
  5130.           return 0;
  5131.      else if (!L->vft->FNdestruct)
  5132.           return 0;
  5133.      else if (!(*L->vft->FNdestruct)(N->data,D))
  5134.           return 0;
  5135.      if (L->front == L->rear)
  5136.           L->rear = FlexN0;
  5137.      else
  5138.           N->next->prev = FlexN0;
  5139.      L->front = N->next;
  5140.      L->nodes--;
  5141.      if (L->curNum)  
  5142.           if (!--L->curNum)
  5143.                L->current = FlexN0;
  5144.      free(N);
  5145.      return 1;
  5146. }
  5147. void * FLtopD(FlexL L, void *D)
  5148. {
  5149.      if (!L) 
  5150.           return (void *) 0;
  5151.      if (!L->front) 
  5152.           return (void *) 0;
  5153.      if (D) if (L->sizeofNodeData)
  5154.           memcpy(D,L->front->data,L->sizeofNodeData);
  5155.      else if (!L->vft)
  5156.           return (void *) 0;
  5157.      else if (!L->vft->FNread)
  5158.           return (void *) 0;
  5159.      else if (!(*L->vft->FNread)(L->front->data,D))
  5160.           return (void *) 0;
  5161.      return L->front->data;
  5162. }
  5163.  
  5164. void * FLinsQN(FlexL L, FlexN N)
  5165. {
  5166.      if (!L || !N) 
  5167.           return (void *) 0;
  5168.      if (L->nodes >= L->maxNodes) 
  5169.           return (void *) 0;
  5170.      N->next = FlexN0;
  5171.      if (L->rear)
  5172.           L->rear->next = N;
  5173.      else
  5174.           L->front = N;
  5175.      N->prev = L->rear;
  5176.      L->rear = N;
  5177.      L->nodes++;
  5178.      L->sorted = 0;
  5179.      return N->data;
  5180. }
  5181.  
  5182. void * FLinsQD(FlexL L, const void *D)
  5183. {
  5184.      FlexN N;
  5185.  
  5186.      if (!L) 
  5187.           return (void *) 0;
  5188.      if (L->nodes >= L->maxNodes) 
  5189.           return (void *) 0;
  5190.      if (L->sizeofNode) {  /*  fixed size FlexNodes  */
  5191.           if ((N = malloc(L->sizeofNode)) == FlexN0)
  5192.                return (void *) 0;
  5193.           if (D) 
  5194.                memcpy(N->data,D,L->sizeofNodeData);
  5195.           else
  5196.                memset(N->data,0,L->sizeofNodeData);
  5197.      }
  5198.      else if (!L->vft || !D)
  5199.           return (void *) 0;
  5200.      else if (!L->vft->FNnew)
  5201.           return (void *) 0;
  5202.      else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
  5203.           return (void *) 0;
  5204.      N->next = FlexN0;
  5205.      if (L->rear)
  5206.           L->rear->next = N;
  5207.      else
  5208.           L->front = N;
  5209.      N->prev = L->rear;
  5210.      L->rear = N;
  5211.      L->nodes++;
  5212.      L->sorted = 0;
  5213.      return N->data;
  5214. }
  5215.  
  5216. void * FLmkcur(FlexL L, unsigned n)
  5217. {
  5218.   if (!L) return (void *) 0;
  5219.   if (!n || (n > L->nodes))  {  /*  out of range  */
  5220.     L->current = 0;
  5221.     L->curNum = 0;
  5222.     return (void *) 0;
  5223.   }
  5224.   else if (n == L->curNum)  /*  already there  */
  5225.     return L->current->data;
  5226.   if (L->current)  /*  divide list into two parts  */
  5227.     if (n > L->curNum)  /*  in last half of list  */
  5228.       if (((L->nodes >> 1) + (L->curNum >> 1)) < n)
  5229.      /*  rear closest */
  5230.      for (L->current = L->rear, L->curNum = L->nodes;
  5231.        L->curNum > n; L->curNum--)
  5232.        L->current = L->current->prev;
  5233.       else  /*  current closest  */
  5234.      for (;L->curNum < n; L->curNum++)
  5235.        L->current = L->current->next;
  5236.     else  /* in first half of list  */
  5237.       if ((L->curNum >> 1) < n)  /*  current closest  */
  5238.      for (;L->curNum > n; L->curNum--)
  5239.        L->current = L->current->prev;
  5240.       else  /*  front closest  */
  5241.      for (L->current = L->front, L->curNum = 1;
  5242.        L->curNum < n; L->curNum++)
  5243.        L->current = L->current->next;
  5244.   else  /*  consider whole list  */
  5245.     if ((L->nodes >> 1) < n)  /*  closer to rear  */
  5246.       for (L->current = L->rear, L->curNum = L->nodes; 
  5247.      L->curNum > n; L->curNum--)
  5248.      L->current = L->current->prev;
  5249.     else  /*  closer to front  */
  5250.       for (L->current = L->front, L->curNum = 1;
  5251.      L->curNum < n; L->curNum++)
  5252.      L->current = L->current->next;
  5253.   return L->current->data;
  5254. }
  5255.  
  5256. void * FLinsN(FlexL L, FlexN N)
  5257. {
  5258.      if (!L || !N) 
  5259.           return (void *) 0;
  5260.      if (L->nodes >= L->maxNodes)
  5261.           return (void *) 0;
  5262.      if ((N->prev = L->current) == FlexN0)  {
  5263.           if ((N->next = L->front) == FlexN0)
  5264.                L->rear = N;
  5265.           else
  5266.                N->next->prev = N;
  5267.           L->front = N;
  5268.      }
  5269.      else  {  /*  after current  */
  5270.           if ((N->next = L->current->next) == FlexN0)
  5271.                L->rear = N;  /*  last node  */
  5272.           else 
  5273.                N->next->prev = N;
  5274.           L->current->next = N;
  5275.      }
  5276.      L->current = N;
  5277.      L->curNum++;
  5278.      L->nodes++;
  5279.      L->sorted = 0;
  5280.      return N->data;
  5281. }
  5282.  
  5283. void * FLinsD(FlexL L, const void *D)
  5284. {
  5285.      FlexN N;
  5286.  
  5287.      if (!L) 
  5288.           return (void *) 0;
  5289.      if (L->nodes >= L->maxNodes) 
  5290.           return (void *) 0;
  5291.      if (L->sizeofNode) {  /*  fixed size FlexNodes  */
  5292.           if ((N = malloc(L->sizeofNode)) == FlexN0)
  5293.                return (void *) 0;
  5294.           if (D) 
  5295.                memcpy(N->data,D,L->sizeofNodeData);
  5296.           else
  5297.                memset(N->data,0,L->sizeofNodeData);
  5298.      }
  5299.      else if (!L->vft || !D)
  5300.           return (void *) 0;
  5301.      else if (!L->vft->FNnew)
  5302.           return (void *) 0;
  5303.      else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
  5304.           return (void *) 0;
  5305.      if ((N->prev = L->current) == FlexN0)  {
  5306.           if ((N->next = L->front) == FlexN0)
  5307.                L->rear = N;
  5308.           else
  5309.                N->next->prev = N;
  5310.           L->front = N;
  5311.      }
  5312.      else  {  /*  after current  */
  5313.           if ((N->next = L->current->next) == FlexN0)
  5314.                L->rear = N;  /*  last node  */
  5315.           else 
  5316.                N->next->prev = N;
  5317.           L->current->next = N;
  5318.      }
  5319.      L->current = N;
  5320.      L->curNum++;
  5321.      L->nodes++;
  5322.      L->sorted = 0;
  5323.      return N->data;
  5324. }
  5325.  
  5326. void * FLinsSortN(FlexL L, FlexN N)
  5327. {
  5328.      unsigned long low, high;
  5329.      void *ok;
  5330.  
  5331.      if (!L || !N) 
  5332.           return (void *) 0;
  5333.      if (L->nodes >= L->maxNodes || !L->compare)
  5334.           return (void *) 0;
  5335.      if (!L->sorted)
  5336.           (void) FLsort(L,FLcompare0);
  5337.      low = 1UL;
  5338.      high = (unsigned long) L->nodes;
  5339.      while (low <= high)  
  5340.           if ((*L->compare)(FLmkcur(L,
  5341.                (unsigned)((low+high) >> 1)),
  5342.                N->data) <= 0)
  5343.                low = (unsigned long)
  5344.                     (L->curNum + 1);
  5345.           else
  5346.                high = (unsigned long)
  5347.                     (L->curNum - 1);
  5348.      (void) FLmkcur(L,(unsigned)high);
  5349.      ok = FLinsN(L,N);
  5350.      L->sorted = 1;
  5351.      return ok;
  5352. }
  5353.  
  5354. void * FLinsSortD(FlexL L, const void *D)
  5355. {
  5356.      FlexN N;
  5357.      unsigned long low, high;
  5358.      void *ok;
  5359.  
  5360.      if (!L || !D) 
  5361.           return (void *) 0;
  5362.      if (L->nodes >= L->maxNodes || !L->compare) 
  5363.           return (void *) 0;
  5364.      if (L->sizeofNode) {  /*  fixed size FlexNodes  */
  5365.           if ((N = malloc(L->sizeofNode)) == FlexN0)
  5366.                return (void *) 0;
  5367.           memcpy(N->data,D,L->sizeofNodeData);
  5368.      }
  5369.      else if (!L->vft)
  5370.           return (void *) 0;
  5371.      else if (!L->vft->FNnew)
  5372.           return (void *) 0;
  5373.      else if ((N = (*L->vft->FNnew)(D)) == FlexN0)
  5374.           return (void *) 0;
  5375.      if (!L->sorted)
  5376.           (void) FLsort(L,FLcompare0);
  5377.      low = 1UL;
  5378.      high = (unsigned long) L->nodes;
  5379.      while (low <= high)  
  5380.           if ((*L->compare)(FLmkcur(L,
  5381.                (unsigned)((low+high) >> 1)),
  5382.                N->data) <= 0)
  5383.                low = (unsigned long)
  5384.                     (L->curNum + 1);
  5385.           else
  5386.                high = (unsigned long)
  5387.                     (L->curNum - 1);
  5388.      (void) FLmkcur(L,(unsigned)high);
  5389.      ok = FLinsN(L,N);
  5390.      L->sorted = 1;
  5391.      return ok;
  5392. }
  5393.  
  5394. FlexN  FLdelN(FlexL L)
  5395. {
  5396.      FlexN N;
  5397.  
  5398.      if (!L) 
  5399.           return FlexN0;
  5400.      if ((N = L->current) == FlexN0)
  5401.           return FlexN0;
  5402.      L->current = N->prev;
  5403.      L->curNum--;
  5404.      if (N->next)
  5405.           N->next->prev = N->prev;
  5406.      else
  5407.           L->rear = N->prev;
  5408.      if (N->prev)
  5409.           N->prev->next = N->next;
  5410.      else
  5411.           L->front = N->next;
  5412.      L->nodes--;
  5413.      N->next = N->prev = FlexN0;
  5414.      return N;
  5415. }
  5416.  
  5417. int FLdelD(FlexL L, void *D)
  5418. {
  5419.      FlexN N;
  5420.  
  5421.      if (!L) 
  5422.           return 0;
  5423.      if ((N = L->current) == FlexN0)
  5424.           return 0;
  5425.      if (L->sizeofNodeData)  {
  5426.           if (D) 
  5427.                memcpy(D,N->data,L->sizeofNodeData);
  5428.      }
  5429.      else if (!L->vft)
  5430.           return 0;
  5431.      else if (!L->vft->FNdestruct)
  5432.           return 0;
  5433.      else if (!(*L->vft->FNdestruct)(N->data,D))
  5434.           return 0;
  5435.      L->current = N->prev;
  5436.      L->curNum--;
  5437.      if (N->next)
  5438.           N->next->prev = N->prev;
  5439.      else
  5440.           L->rear = N->prev;
  5441.      if (N->prev)
  5442.           N->prev->next = N->next;
  5443.      else
  5444.           L->front = N->next;
  5445.      L->nodes--;
  5446.      free(N);
  5447.      return 1;
  5448. }
  5449.  
  5450. void * FLnextD(FlexL L, void *D)
  5451. {
  5452.      FlexN oldCurrent;
  5453.  
  5454.      if (!L) 
  5455.           return (void *) 0;
  5456.      if ((oldCurrent = L->current) != FlexN0)
  5457.           L->current = L->current->next;
  5458.      else
  5459.           L->current = L->front;
  5460.      if (!L->current) {
  5461.           L->curNum = 0;
  5462.           return (void *) 0;
  5463.      }
  5464.      if (D) if (L->sizeofNodeData) 
  5465.           memcpy(D,L->current->data,
  5466.                L->sizeofNodeData);
  5467.      else if (!L->vft) {
  5468.           L->current = oldCurrent;
  5469.           return (void *) 0;
  5470.      }
  5471.      else if (!L->vft->FNread)  {
  5472.           L->current = oldCurrent;
  5473.           return (void *) 0;
  5474.      }
  5475.      else if (!(*L->vft->FNread)(L->current->data,D))  {
  5476.           L->current = oldCurrent;
  5477.           return (void *) 0;
  5478.      }
  5479.      L->curNum++;
  5480.      return L->current->data;
  5481. }
  5482.  
  5483. void * FLprevD(FlexL L, void *D)
  5484. {
  5485.      FlexN oldCurrent;
  5486.      unsigned oldCurNum;
  5487.  
  5488.      if (!L) 
  5489.           return (void *) 0;
  5490.      oldCurNum = L->curNum;
  5491.      if ((oldCurrent = L->current) != FlexN0)  {
  5492.           L->current = L->current->prev;
  5493.           L->curNum--;
  5494.      }
  5495.      else  {
  5496.           L->current = L->rear;
  5497.           L->curNum = L->nodes;
  5498.      }
  5499.      if (!L->current)
  5500.           return (void *) 0;
  5501.      if (D) if (L->sizeofNodeData) 
  5502.           memcpy(D,L->current->data,
  5503.                L->sizeofNodeData);
  5504.      else if (!L->vft)  {
  5505.           L->curNum = oldCurNum;
  5506.           L->current = oldCurrent;
  5507.           return (void *) 0;
  5508.      }
  5509.      else if (!L->vft->FNread)  {
  5510.           L->curNum = oldCurNum;
  5511.           L->current = oldCurrent;
  5512.           return (void *) 0;
  5513.      }
  5514.      else if (!(*L->vft->FNread)(L->current->data,D))  {
  5515.           L->curNum = oldCurNum;
  5516.           L->current = oldCurrent;
  5517.           return (void *) 0;
  5518.      }
  5519.      return L->current->data;
  5520. }
  5521.  
  5522. void * FLfindFirstD(FlexL L, const void *D)
  5523. {
  5524.   unsigned long low, high;
  5525.  
  5526.   if (!L || !D) 
  5527.     return (void *) 0;
  5528.   if (!L->compare)
  5529.     return (void *) 0;
  5530.   if (L->sorted)  {
  5531.     low = 1UL;
  5532.     high = (unsigned long) L->nodes;
  5533.     while (low <= high)  
  5534.       if ((*L->compare)(FLmkcur(L,
  5535.      (unsigned)((low+high) >> 1)),D) < 0)
  5536.      low = (unsigned long) (L->curNum + 1);
  5537.       else
  5538.      high = (unsigned long) (L->curNum - 1);
  5539.     if (FLmkcur(L,(unsigned)high+1))
  5540.       if (!(*L->compare)(L->current->data,D))
  5541.      return L->current->data;
  5542.     /*  leave at insertion point  */
  5543.     (void) FLmkcur(L,(unsigned)high);
  5544.   }
  5545.   else  {
  5546.     (void) FLmkcur(L,0);
  5547.     while (FLnextD(L,(void *)0))
  5548.       if (!(*L->compare)(L->current->data,D))
  5549.      return L->current->data;  
  5550.   }
  5551.   return (void *) 0;
  5552. }
  5553.  
  5554. void * FLfindNextD(FlexL L, const void *D)
  5555. {
  5556.      if (!L || !D) 
  5557.           return (void *) 0;
  5558.      if (!L->compare)
  5559.           return (void *) 0;
  5560.      while (FLnextD(L,(void *)0))
  5561.           if (!(*L->compare)(L->current->data,D))
  5562.                return L->current->data;  
  5563.           else if (L->sorted)
  5564.                break;
  5565.      return (void *) 0;
  5566. }
  5567.  
  5568. void * FLfindLastD(FlexL L, const void *D)
  5569. {
  5570.   unsigned long low, high;
  5571.  
  5572.   if (!L || !D) 
  5573.     return (void *) 0;
  5574.   if (!L->compare)
  5575.     return (void *) 0;
  5576.   if (L->sorted)  {
  5577.     low = 1UL;
  5578.     high = (unsigned long) L->nodes;
  5579.     while (low <= high)  
  5580.       if ((*L->compare)(FLmkcur(L,
  5581.      (unsigned)((low+high) >> 1)),D) <= 0)
  5582.      low = (unsigned long) (L->curNum + 1);
  5583.       else
  5584.      high = (unsigned long) (L->curNum - 1);
  5585.     if (FLmkcur(L,(unsigned)high))
  5586.       if (!(*L->compare)(L->current->data,D))
  5587.      return L->current->data;
  5588.   }
  5589.   else  {
  5590.     (void) FLmkcur(L,0);
  5591.     while (FLprevD(L,(void *)0))
  5592.       if (!(*L->compare)(L->current->data,D))
  5593.      return L->current->data;  
  5594.   }
  5595.   return (void *) 0;
  5596. }
  5597.  
  5598. void * FLfindPrevD(FlexL L, const void *D)
  5599. {
  5600.      if (!L || !D) 
  5601.           return (void *) 0;
  5602.      if (!L->compare)
  5603.           return (void *) 0;
  5604.      while (FLprevD(L,(void *)0))
  5605.           if (!(*L->compare)(L->current->data,D))
  5606.                return L->current->data;  
  5607.           else if (L->sorted)
  5608.                break;
  5609.      return (void *) 0;
  5610. }
  5611.  
  5612. int   FLsort(FlexL L, int (*compare)
  5613.      (const void *D1, const void *D2))
  5614. {
  5615.      FlexList tmp;
  5616.  
  5617.      if (!L) 
  5618.           return 0;
  5619.      if (L->sorted)  {
  5620.           if (L->compare == compare || !compare)
  5621.                { FLmkcur(L,0); return 1; }
  5622.      }
  5623.      else if (!L->compare && !compare) 
  5624.           return 0;
  5625.      if (compare)
  5626.           L->compare = compare;
  5627.      if (!L->nodes)
  5628.           return (L->sorted = 1);
  5629.      (void) FLzero(&tmp);
  5630.      tmp.maxNodes = FLmaxMaxNodes;
  5631.      tmp.sorted = 1;
  5632.      tmp.compare = L->compare;
  5633.      while (L->nodes)
  5634.           (void) FLinsSortN(&tmp,FLpopN(L));
  5635.      L->front = tmp.front;
  5636.      L->rear = tmp.rear;
  5637.      L->nodes = tmp.nodes;
  5638.      return (L->sorted = 1);
  5639. }
  5640.  
  5641. int FLstoreD(FlexL L, const void *D, unsigned n)
  5642. {
  5643.      unsigned oldn;
  5644.  
  5645.      if (!L || !D) 
  5646.           return 0;
  5647.      if (n > L->nodes || !n && !L->current)
  5648.           return 0;
  5649.      if (L->sizeofNodeData)  {
  5650.           if (n) (void) FLmkcur(L,n);
  5651.           memcpy(L->current->data,D,
  5652.                L->sizeofNodeData);
  5653.      }
  5654.      else if (!L->vft)
  5655.           return 0;
  5656.      else if (!L->vft->FNwrite)
  5657.           return 0;
  5658.      else  {
  5659.           oldn = L->curNum;
  5660.           if (n) (void) FLmkcur(L,n);
  5661.           if (!(*L->vft->FNwrite)(L->current->data,D))
  5662.           {
  5663.                (void) FLmkcur(L,oldn);
  5664.                return 0;
  5665.           }
  5666.      }
  5667.      L->sorted = 0;
  5668.      return 1;
  5669. }
  5670.  
  5671. int FLrecallD(FlexL L, void *D, unsigned n)
  5672. {
  5673.      unsigned oldn;
  5674.  
  5675.      if (!L || !D) 
  5676.           return 0;
  5677.      if (n > L->nodes || !n && !L->current)
  5678.           return 0;
  5679.      if (L->sizeofNodeData)  {
  5680.           if (n) (void) FLmkcur(L,n);
  5681.           memcpy(D,L->current->data,
  5682.                L->sizeofNodeData);
  5683.      }
  5684.      else if (!L->vft)
  5685.           return 0;
  5686.      else if (!L->vft->FNread)
  5687.           return 0;
  5688.      else  {
  5689.           oldn = L->curNum;
  5690.           if (n) (void) FLmkcur(L,n);
  5691.           if (!(*L->vft->FNread)(L->current->data,D))
  5692.           {
  5693.                (void) FLmkcur(L,oldn);
  5694.                return 0;
  5695.           }
  5696.      }
  5697.      return 1;
  5698. }
  5699.  
  5700. void * FLpack(FlexL L)  /*  Only fixed nodes!  */
  5701. {
  5702.      long sizeofArray;
  5703.      char *A, *Ai;
  5704.      FlexN N;
  5705.  
  5706.      if (!L) return (void *) 0;
  5707.      sizeofArray = ((long)L->sizeofNodeData)
  5708.           * ((long)L->nodes);
  5709.      if ((sizeofArray <= 0) || 
  5710.           (sizeofArray > FLmaxSizeofArray))
  5711.           return (void *) 0;
  5712.      if ((A = malloc((unsigned) sizeofArray)) 
  5713.           == (char *) 0)
  5714.           return (void *) 0;
  5715.      for (Ai = A, N = L->front; N; N = N->next,
  5716.           Ai += L->sizeofNodeData)
  5717.           memcpy(Ai,N->data,L->sizeofNodeData);
  5718.      return A;
  5719. }
  5720.  
  5721. void **FLpackPtrs(FlexL L)
  5722. {
  5723.      long sizeofArray;
  5724.      void **A;
  5725.      unsigned Ai;
  5726.      FlexN N;
  5727.  
  5728.      if (!L) return (void **) 0;
  5729.      sizeofArray = sizeof(void *) * ((long)L->nodes + 1);
  5730.      if ((sizeofArray <= 0) ||
  5731.           (sizeofArray > FLmaxSizeofArray))
  5732.           return (void **) 0;
  5733.      if ((A = malloc((unsigned) sizeofArray)) 
  5734.           == (void **) 0)
  5735.           return (void **) 0;
  5736.      for (Ai = 0, N = L->front; N; Ai++, N = N->next)
  5737.           A[Ai] = N->data; 
  5738.      A[Ai] = (void *) 0;
  5739.      return A;
  5740. }
  5741.                               Index
  5742.  
  5743.  
  5744. address of operator "&"  11,
  5745.      13, 23, 25
  5746. array functions  14, 21, 26
  5747.  
  5748.  
  5749. binary search algorithm  19,
  5750.      38, 51, 53, 75, 79
  5751. boolean return values  12,
  5752.      18, 34
  5753.  
  5754.  
  5755. compaction  14, 21
  5756. compare function  18
  5757. compatible  24, 26, 57
  5758. constructors  11-14, 24, 25,
  5759.      114, 115
  5760. curNum  109
  5761. current  109
  5762. current node  16-18, 21
  5763. C++  9, 14
  5764.  
  5765.  
  5766. dangling  24, 26, 96, 99
  5767. data in
  5768.      FlexList  112
  5769.      FlexNode  110, 111
  5770. data pointer
  5771.      see value, by
  5772. data length
  5773.      see sizeofNodeData
  5774. destructors  12, 13, 14,
  5775.      114, 115
  5776. different types of data  7,
  5777.      11, 14, see heterogeneous
  5778.      lists
  5779. doubly linked lists  16, 110
  5780.  
  5781.  
  5782. explicitly delete
  5783.      FlexNodes  24, 26
  5784.      other dynamic memory  21
  5785. exploding arrays into
  5786.      FlexLists  14, 21
  5787.  
  5788.  
  5789. FLclear  14, 29, 114, 121
  5790. FLcomparE  20, 114
  5791. FLcompare  15, 16, 18, 30, 115
  5792. FLcompare0  19, 114
  5793. FLcurNum  15, 21, 32, 115
  5794. FLcurrentD  15, 16, 21, 33,
  5795. 115
  5796. FLData  15, 34, 115
  5797. FLDdestruct  36, 42, 43, 114
  5798. FLDdestruct0  43, 114
  5799. FLdelD  35, 116, 135
  5800. FLdelete  14, 36, 115, 123
  5801. FLdelN  37, 116, 134
  5802. FlexL  13, 114
  5803. FlexL0  13, 114
  5804. FlexList
  5805.                                         constructors  11-14, 24,
  5806.                                              25, 114, 115
  5807.                                         destructors  12, 13, 14,
  5808.                                              114, 115
  5809.                                         fields  109, 112
  5810.                                         functions  25-26
  5811.                                         header  14-15, 25, 109-
  5812.                                              112
  5813. FlexN  113
  5814. FlexN0  95, 113
  5815. FlexNode  109-113
  5816. FlexNodeLinkage  109, 113
  5817. FlexNodeVFT  111, 113
  5818. FlexNVFT  57, 113
  5819. FlexNVFT0  57, 114
  5820. FLfindFirstD  18, 38, 116, 138
  5821. FLfindLastD  18, 38, 116, 139
  5822. FLfindNextD  18, 38, 116, 138
  5823. FLfindPrevD  18, 38, 116, 139
  5824. FLfixed  14, 41, 114, 120
  5825. FLfixedNew  14, 42, 115, 122
  5826. FLfrontD  15, 46, 115
  5827. FLinsD  16, 47, 116, 131
  5828. FLinsN  16, 48, 116, 130
  5829. FLinsQD  15, 49, 115, 128
  5830. FLinsQN  15, 50, 115, 127
  5831. FLinsSortD  16, 18, 51 116,
  5832. 133
  5833. FLinsSortN  16, 18, 53, 116,
  5834.                                         132
  5835. FLisFixed  15, 55, 115
  5836. FLisSorted  15, 56, 115
  5837. FLisVariant  15, 57, 115
  5838. FLmallocAlignLoss 107, 116
  5839. FLmaxMaxNodes  58, 116
  5840. FLmaxNodes  15, 58, 115
  5841. FLmkcur  16, 21, 59, 116, 129
  5842. FLnextD  16, 60, 116, 136
  5843. FLnodes  15, 61, 115
  5844. FLnotFull  15, 62, 115
  5845. FLpack  21, 63, 116, 142
  5846. FLpackPtrs  21, 65, 116, 143
  5847. FLpopD  15, 66, 115, 126
  5848. FLpopN  15, 67, 115, 126
  5849. FLprevD  15, 69, 116, 137
  5850. FLpushD  15, 70, 115, 125
  5851. FLpushN  15, 71, 115, 124
  5852. FLrearD  15, 72, 115
  5853. FLrecallD  21, 73, 116, 142
  5854. FLsetCompare  15, 16, 18,
  5855.      75, 115, 124
  5856. FLsetMaxNodes  15, 77, 115,
  5857.      123
  5858. FLsizeofNodeData  15, 78, 115
  5859. FLsort  18, 79, 116, 140
  5860. FLstoreD  21, 81, 116, 141
  5861. FLstr  14, 83, 114, see 
  5862.      FLvariant  93
  5863. FLstrNew  14, 85, 115
  5864. FLtopD  86, 115, 127, see
  5865.      FLfrontD
  5866. FLunpack  14, 21, 87, 114,
  5867.      120 
  5868. FLunpackNew  14, 21, 88, 115,
  5869.      122
  5870. FLunSort  15, 18, 19, 92, 115
  5871. FLvariant  14, 93, 114, 120
  5872. FLvariantNew  14, 102, 115,
  5873.      123
  5874. FNdestruct  93, 114, 118
  5875. FNdestruct0  94, 114
  5876. FNnew  93, 113, 118
  5877. FNnew0  94, 114
  5878. FNread  93, 113, 118
  5879. FNread0  94, 114
  5880. FNwrite  93, 113, 118
  5881. FNwrite0  94, 114
  5882. front  109
  5883.  
  5884.  
  5885. general structure of a
  5886.      FlexList  110-112
  5887.  
  5888.  
  5889. header functions  14-15, 25,
  5890.      109-112
  5891. heterogeneous lists  7, 14,
  5892.      see FLvariant
  5893.  
  5894. imploding FlexLists into
  5895.                                         arrays  21
  5896. inhibit the copying of data
  5897.                                         17, 26
  5898. initialize
  5899.                                         see constructors
  5900.  
  5901.  
  5902. list functions  16, 26
  5903.  
  5904.  
  5905. maxNodes  109,  112
  5906.  
  5907.  
  5908. node, by  15, 23-24, 26
  5909. nodes  109, 112
  5910.  
  5911.  
  5912. OOP  4, 14
  5913.  
  5914.  
  5915. porting FlexList  107, 116
  5916. proprietary techniques  1
  5917.  
  5918.  
  5919. queue functions  15, 25
  5920.  
  5921.  
  5922. rear  109, 112
  5923. reference, by  23, 26
  5924. registration  3
  5925. run time  7
  5926.  
  5927.  
  5928. search algorithm, binary
  5929.                                         see binary search ...
  5930. searching/sorting  18-19, 26
  5931. sequential access  16
  5932. sizeofNode  109, 112
  5933. sizeofNodeData  109, 112
  5934. software license  3
  5935. sorted  109, 112
  5936. sorting/searching
  5937.                                         see searching/sorting
  5938. stack functions  15, 25
  5939. stack-queue-list-array hybrid 
  5940.                                         25-26, 110-111
  5941.  
  5942. unpacking/packing methods
  5943.                                         see compaction
  5944.  
  5945.  
  5946. value, by  23, 26 
  5947. variant list  14,
  5948.      see FLvariant 93
  5949. vft  109, 112
  5950. virtual function table
  5951.      112, see FlexNodeVFT
  5952. void pointer
  5953.      see reference, by
  5954.  
  5955.  
  5956. warranty  3
  5957.  
  5958.          ----------------end-of-author's-documentation---------------
  5959.  
  5960.                          Software Library Information:
  5961.  
  5962.                     This disk copy provided as a service of
  5963.  
  5964.                            Public (software) Library
  5965.  
  5966.          We are not the authors of this program, nor are we associated
  5967.          with the author in any way other than as a distributor of the
  5968.          program in accordance with the author's terms of distribution.
  5969.  
  5970.          Please direct shareware payments and specific questions about
  5971.          this program to the author of the program, whose name appears
  5972.          elsewhere in  this documentation. If you have trouble getting
  5973.          in touch with the author,  we will do whatever we can to help
  5974.          you with your questions. All programs have been tested and do
  5975.          run.  To report problems,  please use the form that is in the
  5976.          file PROBLEM.DOC on many of our disks or in other written for-
  5977.          mat with screen printouts, if possible.  PsL cannot debug pro-
  5978.          programs over the telephone, though we can answer questions.
  5979.  
  5980.          Disks in the PsL are updated  monthly,  so if you did not get
  5981.          this disk directly from the PsL, you should be aware that the
  5982.          files in this set may no longer be the current versions. Also,
  5983.          if you got this disk from another vendor and are having prob-
  5984.          lems,  be aware that  some files may have become corrupted or
  5985.          lost by that vendor. Get a current, working disk from PsL.
  5986.  
  5987.          For a copy of the latest monthly software library newsletter
  5988.          and a list of the 4,000+ disks in the library, call or write
  5989.  
  5990.                            Public (software) Library
  5991.                                P.O.Box 35705 - F
  5992.                             Houston, TX 77235-5705
  5993.  
  5994.                                 1-800-2424-PSL
  5995.                              MC/Visa/AmEx/Discover
  5996.  
  5997.                           Outside of U.S. or in Texas
  5998.                           or for general information,
  5999.                               Call 1-713-524-6394
  6000.  
  6001.  
  6002.